第一部分:注解的基本应用
一、概述
1、注解(annotation)相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,告知编译器该注解处的限定操作。一个注解就是一个类。
2、加上注解后,java编译器,开发工具和其他程序可以用反射来了解程序的类及各种元素上有无任何标记,有什么标记就做什么事。
2、注解可以加在包、类、字段、方法、方法的参数以及局部变量上。
3、注解是Jdk1.5版本出现的新特性。
二、基本注解(java.lang)
1、@SuppressWarnings
指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。注意,在给定元素中取消显示的警告集是所有包含元素中取消显示的警告的超集。例如,如果注释一个类来取消显示某个警告,同时注释一个方法来取消显示另一个警告,那么将在此方法中同时取消显示这两个警告。
根据风格不同,程序员应该始终在最里层的嵌套元素上使用此注释,在那里使用才有效。如果要在特定的方法中取消显示某个警告,则应该注释该方法而不是注释它的类。
String[] value
将由编译器在注释的元素中取消显示的警告集。
示例代码:
加注解前编译结果:(eclipse对过期的方法会加双斜线)package day.day19; /* * 注解的演示 */ public class AnnotationTest { @SuppressWarnings("deprecation")(一个对象) //加上该注解后:表示告知编译器:知道该方法已过时,不需要提示(不检测过期的方法) public static void main(String[] args) { //方法过时,编译器发出警告 System.runFinalizersOnExit(true); } }
2、@Deprecated (过时)
用 @Deprecated 注释的程序元素,表示已过时。不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器会发出警告。
3、@Override(覆盖)
表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。
示例:
第二部分:自定义注解
一、注解应用结构图
二、自定义注解及其反射操作
1、自定义注解
package day.day19; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /* * 自定义注解(在接口前加 @ ) * * 元注解 * 元数据 * 元信息 */ //在注解类上加的注解:元注解 @Retention(RetentionPolicy.RUNTIME)//表示该注解一直保持到运行期间 @Target({ElementType.METHOD,ElementType.TYPE})//@表示该注解能用在方法与类、接口等上 public @interface MyAnnotation { 注解属性; }
2、反射操作:
package day.day19; /* * 应用了自定义注解类的类 */ @MyAnnotation public class AnnotationDemo { /* * 检查指定的类上是否有指定注解 */ public static void main(String[] args) {//此处main方法不属于该类(思想),而是进行反射操作 //检查AnnotationDemo类上是否有MyAnnotation注解 if(AnnotationDemo.class.isAnnotationPresent(MyAnnotation.class)){ //通过反射的方式获取类上的MyAnnotation注解(需要类型转换) MyAnnotation annotation = (MyAnnotation)AnnotationDemo.class.getAnnotation(MyAnnotation.class); System.out.println(annotation); } } }
Class类中的方法:
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果指定类型的注释存在于此元素上,则返回 true,否则返回 false
<A extends Annotation>A getAnnotation(Class<A> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null
Annotation[] getAnnotations() 返回此元素上存在的所有注释
3、@Retention
Retention指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,则保留策略默认为 RetentionPolicy.CLASS。
@Retention的属性value接收的是RetentionPolicy枚举常量,该枚举共三个值:(注解的生命周期)
1)当在java源程序上加了一个注解,接着用javac去编译成class,编译后可能将源程序中的注解给去掉,拿到class文件后就没有注释了。
2)若javac编译器将注解保留到了class文件里面,程序在用class时,先用类加载器去加载class文件到内存中。
3)class文件中的东西不是字节码,只有用类加载器加载后,类加载器对class加载的东西进行处理,如安全检查等。处理完后到内存中的东西才是字节码。
4)类加载器在把class文件调用内存的过程中也有转换,转换的时候决定是否将class文件中的注解保留下来。
5)扫描具体类上有什么方法是RUNTIME
4、@Target
指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。
@Target(value)的属性value接收的是ElementType枚举常量,该枚举中的值有:
第三部分:为注解增加基本属性
一、概述
二、注意事项一个注解相当于一个胸牌,如果胸前贴了胸牌,就是传智播客的学生,否则,就不是。如果还想区分出是具体哪个班的学生,这时候就可以为胸牌再增加一个属性来进行区分。
1、注解属性支持八个基本类型、String、Class、enum、annotation及上述类型的数组
2、定义注解的属性类似在接口中增加一个方法。如 String color(),使用方式为:@MyAnnotation(color="blue")
3、注解中的属性可以设置默认值。如 String color() default "red";
4、如果在使用注解时,注解的属性中有部分未定义默认值,在使用时必须指定。
5、调用属性时类似对象调用方法。如(注解对象)annotation.color()
6、如果注解中有只有一个value属性(String value()),或者有其他属性但是其他属性都有默认值,那么在使用注解时可以省略 value= ,写成@MyAnnotation("bed")
7、如果注解中有数组属性,如int[] arrayAnno() default {1,2,3}; 当数组中只有一个元素时,可以省略大括号,如@MyAnnotation(arrayAnno=7)
8、在程序同添加的注解(如@MyAnnotation(color="black") 都相当于注解(类似接口的)一个实例对象
9、如果注解属性还是一个注解,属性值用@...表示(一个注解对象)
三、示例代码
注解属性:
package day.day19; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import day.day17.EnumTest; import day.day17.EnumTest.SeasonEnum; /* * 为注解添加属性 */ /* * Retention中有一个value属性,该方法返回值为RetentionPolicy类型的 枚举 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD,ElementType.TYPE})//数组只有一个元素时,可以省略大括号 public @interface MyAnnotation { String color() default "blue";//为注解添加属性(和在接口中定义方法一样)-- 添加默认属性 /* * 如果注解中只有一个value属性,(没有color属性)那么在使用注解时,value= 可用省略不写,如:@MyAnnotation("abc") */ String value()default "value!!"; int[] arrayAttr() default {2,3,4};//数组 /* * 该枚举是类似一个内部类(非静态,定义在一个类的成员位) */ EnumTest.SeasonEnum enumValue() default EnumTestSeasonEnum.SPRING;//枚举类型,默认值中省略了外部类名 //属性还是一个注解(注解中有只有一个属性value) 注解的值为@MetaAnnotation(...) MetaAnnotation annotationArr() default @MetaAnnotation("默认"); }
注解使用:
package day.day19; import java.util.Arrays; import day.day17.EnumTest; import day.day17.EnumTest.SeasonEnum; /* * 应用了自定义注解类的类 * //数组只有一个值时可以省略{} */ @MyAnnotation(color="red",arrayAttr=7,enumValue=SeasonEnum.SUMMER,annotationArr=@MetaAnnotation("OK!!")) public class AnnotationDemo { @MyAnnotation("guiyang")//只有一个value属性时,或者其他属性有default时 public static void main(String[] args) { //检查AnnotationDemo类上是否有MyAnnotation注解 if(AnnotationDemo.class.isAnnotationPresent(MyAnnotation.class)){ //通过反射的方式获取类上的MyAnnotation注解(需要类型转换) MyAnnotation annotation = (MyAnnotation)AnnotationDemo.class.getAnnotation(MyAnnotation.class); //获取属性(累是调用方法) System.out.println(annotation.enumValue()); System.out.println(annotation.annotationArr().value()); } } }