注解理解
注释是为了向以后阅读这份代码的人解释说明一些事情,注解是注释的升级版,它可以向编译器、虚拟机等解释说明一些事情。
注解是描述Java代码的代码,它能够被编译器解析,注解处理工具在运行时也能够解析注解。
注解比java注释和Javadoc要强大得多,它们三者之间的重大的区别在于,Java注释和Javadoc描述所发挥的作用仅仅到编译时就止步了,而注解直到运行时都能够发挥作用。
注解为我们提供了为类/方法/属性/变量添加描述信息的更通用的方式,而这些描述信息对于开发者、自动化工具、Java编译器和Java运行时来说都是有意义的,也就是说他们都能“读懂”注解信息。
除了传递信息,我们也可以使用注解生成代码。我们可以使用注解,然后让注解解析工具来解析它们,以此来生成一些”模板化“的代码。
注解的分类
根据注解参数的个数,我们可以将注解分为三类:
1.标记注解:一个没有成员定义的Annotation类型被称为标记注解。这种Annotation类型仅使用自身的存在与否来为我们提供信息。比如后面的系统注解@Override;
2.单值注解
3.完整注解
根据注解使用方法和用途,我们可以将Annotation分为三类:
1.JDK内置系统注解
2.元注解
3.自定义注解
元注解
元注解即用来描述注解的注解
Docemented
当一个注解类型被@Documented元注解所描述时,那么无论在哪里使用这个注解,都会被Javadoc工具文档化。我们来看一下它的定义:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }
定义注解使用@interface关键字
这个元注解被@Documented修饰,表示它本身也会被文档化。 @Retention元注解的值RetentionPolicy.RUNTIME表示@Documented这个注解能保留到运行时;@Target元注解的值ElementType.ANNOTATION_TYPE表示@Documented这个注解只能够用来描述注解类型。
Inherited
表明被修饰的注解类型是自动继承的。具体解释如下:若一个注解类型被Inherited元注解所修饰,则当用户在一个类声明中查询该注解类型时,若发现这个类声明中不包含这个注解类型,则会自动在这个类的父类中查询相应的注解类型,这个过程会被重复,直到该注解类型被找到或是查找完了Object类还未找到。这个元注解的定义如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }
这个元注解类型被@Documented所注解,能够保留到运行时,只能用来描述注解类型。
Retention
它表示一个注解类型会被保留到什么时候,比如以下代码表示Developer注解会被保留到运行时:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }
我们在使用@Retention时,后面括号里的内容即表示他的取值,从以上定义我们可以看到,取值的类型为RetentionPolicy,这是一个枚举类型,它可以取以下值:
* SOURCE:表示在编译时这个注解会被移除,不会包含在编译后产生的class文件中;
* CLASS:表示这个注解会被包含在class文件中,但在运行时会被移除;
* RUNTIME:表示这个注解会被保留到运行时,在运行时可以JVM访问到,我们可以在运行时通过反射解析这个注解。
Target
这个元注解说明了被修饰的注解的应用范围,也就是被修饰的注解可以用来注解哪些程序元素,它的定义如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { /** * Returns an array of the kinds of elements an annotation type * can be applied to. * @return an array of the kinds of elements an annotation type * can be applied to */ ElementType[] value(); }
看到它也会保留到运行时,而且它的取值是为ElementType[]类型(一个数组,意思是可以指定多个值),ElementType是一个枚举类型,它可以取以下值:
- TYPE:表示可以用来注解类、接口、注解类型或枚举类型;
- PACKAGE:可以用来注解包;
- PARAMETER:可以用来注解参数;
- ANNOTATION_TYPE:可以用来注解 注解类型;
- METHOD:可以用来注解方法;
- FIELD:可以用来注解属性(包括枚举常量);
- CONSTRUCTOR:可以用来注解构造器;
- LOCAL_VARIABLE:可用来注解局部变量。
自定义注解
自定义的注解需要解析工具来解析。注解的定义接近接口形式。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface AliasFor { /** * Alias for {@link #attribute}. * <p>Intended to be used instead of {@link #attribute} when {@link #annotation} * is not declared — for example: {@code @AliasFor("value")} instead of * {@code @AliasFor(attribute = "value")}. */ @AliasFor("attribute") String value() default ""; /** * The name of the attribute that <em>this</em> attribute is an alias for. * @see #value */ @AliasFor("value") String attribute() default ""; /** * The type of annotation in which the aliased {@link #attribute} is declared. * <p>Defaults to {@link Annotation}, implying that the aliased attribute is * declared in the same annotation as <em>this</em> attribute. */ Class<? extends Annotation> annotation() default Annotation.class; }
在定义注释时的注意事项:
注解类型是通过 @interface关键字定义的
在”注解体“中,所有的方法均没有方法体且只允许public和abstract这两种修饰符号(不加修饰符缺省为public),注解方法不允许有throws子句;
注解方法的返回值只能为以下几种:原始数据类型), String, Class, 枚举类型, 注解和它们的一维数组,可以为方法指定默认返回值。
注解之中只能声明方法,不能声明字段。
使用注解:
给注解传值,给指定的注解方法传值需要指定注解方法名。
通过反射来提取注解:
java.lang.reflect.AnnotatedElement 注解元素
已知实现类:
Class, Method, Filed, Constructor, Package
可以提供此接口实现类注解的完美提取。