Annotation注解
注解
Annotation(注解)概述
从JDK5.0开始,Java增加了对元数据(MetaData)的支持,也就是Annotation(注解)。
Annotation其实就是代码里的特殊标记,它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。
掌握注解技术的要点:
如何定义注解。
如何反射注解,并根据反射的注解信息,决定如何去运行类。
了解注解及java提供的几个基本注解
@SuppressWarnings:抑制编译器警告。
首先编写一个AnnotationTest类,先通过@SuppressWarnings的应用让大家认识和了解一下注解,通过System.runFinalizersOnExit(true);的编译警告引出@SuppressWarnings("deprecation")。
publicclassAnnotationTest{
@SuppressWarnings("deprecation")
publicstaticvoidmain(String[]args){
System.runFinalizersOnExit(true);
}
}
@Deprecated:用于表示某个程序元素(类,方法等)已过时。
接着直接在刚才的类中增加一个方法,并加上@Deprecated标注,在另外一个类中调用这个方法。
publicclassAnnotationTest{
@SuppressWarnings("deprecation")
publicstaticvoidmain(String[]args){
System.runFinalizersOnExit(true);
}
@Deprecated
publicstaticvoidsayHello(){
System.out.println("hi,李阿昀");
}
}
@Override:限定重写父类方法,该注解只能用于方法。
表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。
publicbooleanequals(Reflectother)方法与HashSet结合讲解。
总结:注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
注解的应用结构图
注解就相当于一个你的源程序中要调用的一个类,要在源程序中应用某个注解,得先准备好了这个注解类,就像你要调用某个类,得先要开发好这个类。
自定义注解及其应用
定义新的Annotation类型使用@interface关键字。
定义一个最简单的注解:
public@interfaceItcastAnnotation{
}
把它加在某个类上:
@ItcastAnnotation
publicclassAnnotationTest{
@SuppressWarnings("deprecation")
publicstaticvoidmain(String[]args){
System.runFinalizersOnExit(true);
}
@Deprecated
publicstaticvoidsayHello(){
System.out.println("hi,李阿昀");
}
}
用反射进行测试AnnotationTest的定义上是否有@ItcastAnnotation:
@ItcastAnnotation
publicclassAnnotationTest{
@SuppressWarnings("deprecation")
publicstaticvoidmain(String[]args){
System.runFinalizersOnExit(true);
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){//类上是否有注解,默认情况下返回false
ItcastAnnotationannotation=(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation);
}
}
@Deprecated
publicstaticvoidsayHello(){
System.out.println("hi,李阿昀");
}
}
发现控制台无任何反应,根据反射测试的问题,引出@Retention元注解的讲解。
@Retention元注解
只能用于修饰一个Annotation的定义,用于指定该Annotation可以保留的域,@Rentention包含一个RetentionPolicy类型的成员变量,通过这个变量指定域。其有三种取值:
RetetionPolicy.SOURCE:编译器直接丢弃这种策略的注解。
RetetionPolicy.CLASS:编译器将把注解记录在class文件中,当运行Java程序时,JVM不会保留注解。这是默认值。
RetetionPolicy.RUNTIME:编译器将把注解记录在class文件中。当运行Java程序时,JVM会保留注解,程序可以通过反射获取该注解。
分别对应:java源文件→class文件→内存中的字节码。也即一个Java类具有3种状态:
编译JVM装载进内存
.java------------------->.class------------------->运行时(内存里面的java类)
1
2
对@Retention元注解更加细致的解释:
当在java源程序上加入注解,此源程序接着要由javac去编译,javac把源文件编译成.class时,可能会把源程序上的一些注解给去掉,此时.class文件里面就没有注解了,这是一种可能。
假设javac编译器把注解留在.class文件里面,结果我们的程序在使用.class时,要由类加载器把.class文件给调到内存里来,只有把.class文件加载到内存里来之后,类加载器加载完了之后,类加载器会对.class文件进行处理,安全检查等,处理完了之后,在内存中最终的二进制文件才是字节码,类加载器在把.class文件调到内存的过程中,也有转换,转换的时候是否把.class文件里面的注解保留下来,这也是一种可能。
所以,一个注解的生命周期有3个阶段。
我们定义的简单注解修改为如下:
@Retention(RetentionPolicy.RUNTIME)
public@interfaceItcastAnnotation{
}
就能正确打印了。
结论:我们写一个注解的目的,主要是用来替换配置文件,我们希望这个类在运行时获得注解配置的信息,来运行我这个类,想要注解配置的信息能够让类在运行时获取到,那就一定要把这个注解声明在运行时。
思考:@Override、@SuppressWarnings和@Deprecated这三个注解的属性值分别是什么?
答:
@Override→RetetionPolicy.SOURCE
@SuppressWarnings→RetetionPolicy.SOURCE
@Deprecated→RetetionPolicy.RUNTIME
@Target元注解
指定注解用于修饰类的哪个成员。@Target包含了一个名为value,类型为ElementType的成员变量。如若声明注解时,没指定@Target,默认该注解可以作用在类的所有成员上。
Target的默认值为任何元素,设置Target等于ElementType.METHOD,原来加在类上的注解就报错了,改为用数组方式设置{ElementType.METHOD,ElementType.TYPE}就可以了,表示此注解既可以在方法上使用,也可在类上使用。
@Documented元注解
用于指定被该元Annotation修饰的Annotation类将被javadoc工具提取成文档。
@Inherited元注解
被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
注意:元注解以及其枚举属性值不用记,只要会看JDK提供那几个基本注解的API帮助文档的定义或其源代码,按图索骥即可查到,或者直接看java.lang.annotation包下面的类。
为注解增加基本属性
注解属性的作用:原来写在配置文件中的信息,可以通过注解的属性进行描述。
什么是注解的属性
一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是传智播客的学生,否则,就不是。如果还想区分出是传智播客哪个班的学生,这时候可以为胸牌在增加一个属性来进行区分。加了属性的标记效果为:@ItcastAnnotation(color="red")
定义基本类型的属性和应用属性
在注解类中增加Stringcolor():
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public@interfaceItcastAnnotation{
Stringcolor();
}
用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法:
@ItcastAnnotation(color="red")
publicclassAnnotationTest{
@SuppressWarnings("deprecation")
publicstaticvoidmain(String[]args){
System.runFinalizersOnExit(true);
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){//类上是否有注解,默认情况下返回false
ItcastAnnotationannotation=(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.color());//red
}
}
@Deprecated
publicstaticvoidsayHello(){
System.out.println("hi,李阿昀");
}
}
可以认为上面这个@ItcastAnnotation(color=”red”)是ItcastAnnotation类的一个实例对象。
为属性指定缺省值:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public@interfaceItcastAnnotation{
Stringcolor()default"blue";
}
value属性:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public@interfaceItcastAnnotation{
Stringcolor()default"blue";
Stringvalue();
}
用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法:
@ItcastAnnotation(color="red",value="abc")
publicclassAnnotationTest{
@SuppressWarnings("deprecation")
@ItcastAnnowww.shanxiwang.nettation("xyz")
publicstaticvoidmain(String[]args){
System.runFinalizersOnExit(true);
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){//类上是否有注解,默认情况下返回false
ItcastAnnotationannotation=(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.value());//abc
}
}
@Deprecated
publicstaticvoidsayHello(){
System.out.println("hi,李阿昀");
}
}
注意:如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值或者你只有一个value属性),那么可以省略value=部分,例如:@ItcastAnnotation("lhm")。
为注解增加高级属性
数组类型的属性
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public@interfaceItcastAnnotation{
Stringcolor()default"blue";
Stringvalue();
int[]arrayAttr()default{3,4,4};
}
用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法:
@ItcastAnnotation(color="red",value="abc",arrayAttr=1)
publicclassAnnotationTest{
@SuppressWarnings("deprecation")
@ItcastAnnotation("xyz")
publicstaticvoidmain(String[]args){
System.runFinalizersOnExit(true);
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){//类上是否有注解,默认情况下返回false
ItcastAnnotationannotation=(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.arrayAttr().length);//1
}
}
@Deprecated
publicstaticvoidsayHello(){
System.out.println("hi,李阿昀");
}
}
注意:如果数组属性中只有一个元素,这时候属性值部分可以省略大括号。
枚举类型的属性
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public@interfaceItcastAnnotation{
Stringcolor()default"blue";
Stringvalue();
int[]arrayAttr()default{3,4,4};
EnumTest.TrafficLamplamp()defaultEnumTest.TrafficLamp.RED;
}
用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法:
@ItcastAnnotation(color="red",value="abc",arrayAttr=1)
publicclassAnnotationTest{
@SuppressWarnings("deprecation")
@ItcastAnnotation("xyz")
publicstaticvoidmain(String[]args){
System.runFinalizersOnExit(true);
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){//类上是否有注解,默认情况下返回false
ItcastAnnotationannotation=(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.lamp().nextLamp().name());//GREEN
}
}
@Deprecated
publicstaticvoidsayHello(){
System.out.println("hi,李阿昀");
}
}
注解类型的属性:
我们再定义一个注解MetaAnnotation:
public@interfaceMetaAnnotation{
Stringvalue();
}
接着再定义一个注解类型的属性:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public@interfaceItcastAnnotation{
Stringcolor()default"blue";
Stringvalue();
int[]arrayAttr()default{3,4,4};
EnumTest.TrafficLamplamp()defaultEnumTest.TrafficLamp.RED;
MetaAnnotationannotationAttr()default@MetaAnnotation("lhm");
}
枚举和注解都是特殊的类,不能用new创建它们的实例对象,创建枚举的实例对象就是在其中增加元素。在程序中如何创建出一个注解的实例对象啊?直接用@放上一个标记即可,例如:@MetaAnnotation("lhm")。
用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法:
@ItcastAnnotation(annotationAttr=@MetaAnnotation("flx"),color="red",value="abc",arrayAttr=1)
publicclassAnnotationTest{
@SuppressWarnings("deprecation")
@ItcastAnnotation("xyz")
publicstaticvoidmain(String[]args){
System.runFinalizersOnExit(true);
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){//类上是否有注解,默认情况下返回false
ItcastAnnotationannotation=(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.annotationAttr().value());//flx
}
}
@Deprecated
publicstaticvoidsayHello(){
System.out.println("hi,李阿昀");
}
}
可以认为@ItcastAnnotation是ItcastAnnotation类的一个实例对象,同样的道理,可以认为@MetaAnnotation是MetaAnnotation类的一个实例对象。
|
|