【框架基础】:全面解析Java注解(一)

来源:互联网 发布:ubuntu复制到命令行 编辑:程序博客网 时间:2024/05/02 02:50

       Java注解概述

       要了解Java注解要先知道Java的反射,反射是运行时获取类的成员,注解也是类的成员,以此达到动态编码的效

果,多用在框架,或者使用框架时候添加注解让框架调用。

       注解定义:注解(Annotation),也叫元数据。Java提供了一种原程序中的元素关联任何信息和任何元数据的途

径和方法,一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可

以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

       Annotation(注解)是JDK1.5及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译

时检查。注解是以‘@注解名’在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注

解、完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实

现对这些元数据(用来描述数据的数据)的访问。另外,你可以在编译时选择代码里的注解是否只存在于源代码级,

或者它也能在class文件、或者运行时中出现(SOURCE/CLASS/RUNTIME)。

       注解的作用

       如果要对于注解的作用进行分类,还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类:

       编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】

       代码分析:通过代码里标识的元数据对代码进行分析【使用反射】

       编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

       为什么学习注解

       1、能够读懂别人写的代码,特别是框架相关的代码,增加代码的阅读性;

       2、让编程更加简洁,代码更加清晰,理清自己的思路;

       3、生成API文档;

       Java中的常见注解

       JDK内置注解

       

       @Override

       它的作用是对覆盖超类中方法的方法进行标记,如果被标记的方法并没有实际覆盖超类中的方法,则编译器会发

出错误警告。下面的例子是实现类Child实现了接口Person的方法   使用了@Override。

package com.demo.annotation;/** * 测试@Override注解 * @author Administrator * @date 2016年12月9日 */public interface Person {public String name();public int age();public void sing();}class Child implements Person {@Overridepublic String name() {// TODO Auto-generated method stubreturn null;}@Overridepublic int age() {// TODO Auto-generated method stubreturn 0;}@Overridepublic void sing() {// TODO Auto-generated method stub    }}

        @Deprecated

        它的作用是对不应该再使用的方法添加注解,当编程人员使用这些方法时,将会在编译时显示提示信息,它与

javadoc里的@deprecated标记有相同的功能,准确的说,它还不如javadoc @deprecated,因为它不支持参数,

使用@Deprecated的示例代码示例如下:   

package com.demo.annotation;/** * 测试@Deprecated注解 * @author Administrator * @date 2016年12月9日 */public interface Person {public String name();public int age();@Deprecatedpublic void sing();}class Child implements Person {@Overridepublic String name() {// TODO Auto-generated method stubreturn null;}@Overridepublic int age() {// TODO Auto-generated method stubreturn 0;}@Overridepublic void sing() {// TODO Auto-generated method stub}}class Test {@SuppressWarnings("deprecation")public void sing(){Person person = new Child();person.sing();//sing()方法已经过时}}

        Person接口使用了@Deprecated修饰了一个已经过时的方法,此时强行调用超类继承来的方法就会有个代码过

时的横线,并且报一个代码过时的警告,但不会影响正常使用。如果要去掉警告可以使用

 @suppressWarings("deprecation")  来忽略这个警告。

       @SuppressWarnings

       其参数有:
       deprecation:使用了过时的类或方法时的警告

       unchecked:执行了未检查的转换时的警告

       fallthrough:当 switch 程序块直接通往下一种情况而没有 break 时的警告

       path:在类路径、源文件路径等中有不存在的路径时的警告

       serial:当在可序列化的类上缺少serialVersionUID 定义时的警告

       finally :任何 finally 子句不能正常完成时的警告

       all:关于以上所有情况的警告

       这里的演示在上面已经出现过。

       

       常见的第三方注解

       

       在这里只是简单的演示一下,在学习框架的过程中再详细说明。

       按照过去的方式就是写一个配置文件:

       

       使用注解方式不再使用配置文件:

       

       Java注解的分类

       按照运行机制分类

       源码注解:注解只在源码中存在,编译成.class文件就不存在了;

       编译时注解:注解在源码和.class文件中都存在,比如@SuppressWarnings、@Override和@Deprecated只在

编译时刻起作用;

       运行时注解:源码、编译后以及运行时都存在的注解,在运行阶段还起作用,甚至会影响运行逻辑的注解,比如

spring框架的@Autowired注解。

       按照来源分类

       来自JDK的注解:@SuppressWarnings、@Override和@Deprecated

       来自第三方的注解:比如spring框架的@Autowired注解

       自定义注解:我们自己定义的注解。

       元注解

       注解的注解:自定义注解中比较常见。

       Java自定义注解

       先来看一个模板:

       

        自定义注解语法要求

       1)使用@Interface关键字定义注解;

       2)成员以无参无异常方式声明;

       3)可以用default为成员指定一个默认值;

       4)成员类型是受限的,合法的类型包括原始类型及String、Class、Annotation、Enumeration;

       5)如果注解只有一个成员,则成员必须取名为value(),在使用时可以忽略成员名和赋值号(=);

       6)注解类可以没有成员,没有成员的注解称为标识注解;

        注解的注解(元注解)

       @Target({ElementType.METHOD,ElementType.TYPE})

       CONSTRUCTOR:构造方法声明
       FIELD:字段声明
       LOACL_VARIABLE:局部变量声明
       METHOD:方法声明
       PACKAGE:包声明
       PARAMETER:参数声明
       TYPE:类或者接口声明

       @Retention(RetentionPolicy.RUNTIME)

       SOURCE:只在源码显示,编译时会丢弃

       CLASS:编译时会记录到class中,运行时忽略

       RUNTIME:运行时存在,可以通过反射读取

       @Inherited

       允许子类继承

       @Documented

       生成javadoc时会包含注解

       使用自定义注解

       使用注解的语法:@<注解名>(<成员名1>=<成员值1>,<成员名2>=<成员值2>,...)

       一个简单的例子:

       定义@Description注解:

package com.demo.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.METHOD,ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface Description {String desc();String author();int age() default 18;}

       使用注解:

package com.demo.annotation;@Description(desc="I am class annotation",author="Mooc boy",age=18)public class AnnotationTest {@Description(desc="I am method annotation",author="Mooc boy",age=18)public String eyeColor(){return "red";}}

       @Description注解在eyeColor()方法上使用,可以在类或者接口上使用

       解析注解

       概念:通过反射获取类,函数或成员上的运行时注解信息,从而实现动态控制控制程序运行的逻辑。

       对于@RetentionRetention表示作用范围,我们知道:SOURCE表示只在源码显示,编译时会丢弃;

CLASS表示编译时会记录到class中,运行时忽略;RUNTIME表示运行时存在,可以通过反射读取。前两个都不会显

示结果,只有最后一个会显示结果。

       一个例子:

package com.demo.annotation;import java.lang.annotation.Annotation;import java.lang.reflect.Method;/** * 解析注解 * @author Administrator * @date 2016年12月9日 */public class Demo {public static void main(String[] args) {//1.使用类加载器加载类try {Class< ?> clazz = Class.forName("com.demo.annotation.AnnotationTest");    //2.找到类上面的注解boolean flag1 = clazz.isAnnotationPresent(Description.class);if(flag1){//3.拿到注解实例Description description1 = (Description)clazz.getAnnotation(Description.class);System.out.println(description1.desc());System.out.println(description1.author());System.out.println(description1.age());}//4.解析找到方法上的注解Method[] methods = clazz.getMethods();for (Method method : methods) {boolean flag2 = method.isAnnotationPresent(Description.class);if(flag2){//5.拿到注解实例Description description2 = (Description)method.getAnnotation(Description.class);System.out.println(description2.desc());System.out.println(description2.author());System.out.println(description2.age());}}//另外一种解析方法for (Method method : methods) {Annotation[]  annotations = method.getAnnotations();for (Annotation annotation : annotations) {if(annotation instanceof Description){Description description3 = (Description)annotation;System.out.println(description3.desc());System.out.println(description3.author());System.out.println(description3.age());}}}} catch (ClassNotFoundException e) {e.printStackTrace();}}}

       运行结果:

       

       关于@Inherited元注解

       父子类继承注解这块分两种情况,一个是注解定义了@Inherited,一个是没定义。在每种情况中又分类上的注

解,子类实现父类抽象方法,继承了父类方法,覆盖了父类方法这四种情况,具体继承规则如下:

       编写自定义注解时未写@Inherited的运行结果:        

       子类的类上能否继承到父类的类上的注解?    否        

       子类方法,实现了父类上的抽象方法,这个方法能否继承到注解?    否        

       子类方法,继承了父类上的方法,这个方法能否继承到注解?    能        

       子类方法,覆盖了父类上的方法,这个方法能否继承到注解?    否        

       编写自定义注解时写了@Inherited的运行结果:

       子类的类上能否继承到父类的类上的注解?     能    

       子类方法,实现了父类上的抽象方法,这个方法能否继承到注解?      否    

       子类方法,继承了父类上的方法,这个方法能否继承到注解?      能    

       子类方法,覆盖了父类上的方法,这个方法能否继承到注解?      否   

        仅供参考!


1 0
原创粉丝点击