从jdk5开始,java增加了对元数据的支持。也就是Annotation,注解。其实是代码里的特殊标记,这些标记在编译,类加载,运行时被读取,并执行相应的处理。
注解是一个接口,程序可以通过反射来获取指定程序元素dejava.lang.annotation.Annotation对象,通过对象来取得注解里的元数据。
注解能被用啦为程序元素(类,方法,成员变量等)设置元数据。
基本注解
@Override
@Deprecated:Java 9改进了该注解,该注解支持since、forRemoval两个属性。
@SuppressWarnings
@SafeVarargs:Java 9增强了该注解,允许该注解修饰私有实例方法
@FunctionalInterface
这5个第四个是java7新增,最后一个是java8新增。都在java.lang包下。
@Override用来指定方法覆盖。
@Deprecated用于表示某个程序元素已过时。当其他程序使用已过时的类,方法时,编译器会给出警告。java9增加了since表示从那个版本指定为过时,forRemoveal是boolean类型,true代表未来会删除。
@SuppressWarnings 指示该注解修饰的程序元素及该元素的所有子元素,取消显示指定的编译器警告。
@SafeVarargs用于抑制“堆污染”警告。
@Functionallnterface用来指定某个接口必须是函数式接口。
JDK的元注解
@Retention用于指定被修饰的注解可以保留多长时间。,包含一个类型为value的成员变量。只有value为RetentionPolicy.RUNTIME时,JVm可以获取注解信息,程序可以通过反射获取注解信息
使用@Target修饰注解定义,用于指定被修饰的注解能用于修饰哪些线程单元。
使用@Documented用于指定被该元注解修饰的注解类将被javadoc工具提取成文档。
使用@Inherited指定它修饰的注解将具有继承性。
自定义注解
定义新的注解类型使用@interface关键字
public @interface Test{//定义注解采用@interface来定义,这个注解接口继承了java.annotation.Annotation接口 String name();//采用没有形参的方法来定义注解的成员变量,返回值表示注解的类型 int age() default 34;//可以为成员变量指定默认值。 } @Test(name="stu",age=12)//注解可以修饰类,接口,方法等任何元素。一旦定注解定义了成员变量,那么就一定要为他赋值。 public class MyClass{ @Test(name="stu")//使用了默认值的成员变量可以不为之指定值 public void info(){ //标记注解:没有定义成员变量的注解,仅利用自身的存在与否来提供信息 //元数据注解:包含成员变量的注解。可以接受更多的元数据。 } }
注解需要由开发者提供相应的工具来提取处理注解信息
java使用java.lang.annotation.Annotation接口来代表程序元素签名的注解。java5在java.lang.reflect包下新增了AnnotatedElement接口,代表程序中可以接受注解的程序元素。
该包下包含一些实现反射功能的工具类。只有当定义注解时,是用了@Retention的Runtime模式,该注解才能在运行时可见,JVM才会在装在class文件时读取保存在class文件中的注解信息。
AnnotatedElement接口是所有程序元素如class,MEthod等的父接口。所以程序通过反射获取了某个类的该接口对象。之后,程序就可以调用该对象的如下几个方法来访问注解信息。
getAnnotation。。。等等。
仅仅使用注解标记程序元素,对程序不会有任何影响,为了让注解起作用,必须为这些注解提供一个注解处理工具。
工具通过反射来获取标记,获取这些标记后,程序可以做出相应的处理。对于标记注解,程序通过判断该注解存在与否,决定是否允许指定方法。
重复注解,java8以前,同一个元素前面最多只能使用一个相同类型的注解,如果使用多个,必须使用注解容器。
从java8开始,允许使用多个相同的类型的注解来修饰同一个类。但是需要开发。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Repeatable(FkTags.class) public @interface FkTag { // 为该注解定义2个成员变量 String name() default "疯狂软件"; int age(); } // 指定该注解信息会保留到运行时 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FkTags { // 定义value成员变量,该成员变量可接受多个@FkTag注解 FkTag[] value(); }
使用@Repeatable是注解可以重复。
然后定义该注解的容器。
注解容器的的保留期必须比它所包含的注解保留期更长。
重复注解只是一种简化写法,其实多个重复注解会被作为容器注解的value成员变量的数组元素。
类型注解
java8位ElementType增加了两个枚举值。这样允许定义枚举是使用@target(TYPE_USE)修饰符。可以在任何地方出现类型注解。使得程序执行更严格的类型检查。但是只写注解没有作用,需要使用注解处理工具。第三方框架一般会提供类型注解检查工具。
APT,是一种注解处理工具,他对源代码文件进行检测,找出源文件所包含的注解信息,然后针对注解信息进行额外处理。
处理注解时,可以根据源文件中的注解生成额外的源文件和其他的文件,还会编译生成的源代码文件和原来的源文件,将他们一起生成class文件。
简化开发者工作量,APT可以在编译程序源代码同时生成一些附属文件。
java提供的javac.exe工具有一个-processor选项,可以指定一个注解处理器,会在编译时提取并处理java源文件中的注解。