一、了解和入门-注解的应用
了解注解及java提供的几个基本注解。
jdk1.5的新特性(很重要)未来的开发模式基本是基于注解(struts2一部分,spring...)(程序放在新建的包cn.itcast.day2中)
先通过@SuperessWarnings的应用让大家直观地了解注解:
通过System.runFinalizersOnExit(true);的编译警告引出@SupperessWarnings(“deprecation”)
建一个新的类AnnotationTest,main方法加入System.runFinalizersOnExit(true);
eclipse可以直观的表示出,它是deprecated的
但是在命令行中怎么显示:
首先set path-C:\Java\jdk......\bin;%path%; (每个人jdk版本不一样)
然后切换到当前类所在的目录,编译:javac AnnotationTest.java后,屏幕显示:
注意:AnnotationTest.java使用或覆盖了已过时的API。
注意:要了解纤细信息,请使用-Xline:deprecation重新编译
因此我们重新编译:javac -Xline:deprecation AnnotationTest.java,屏幕就会显示出具体信息。
要是还想用这个过时的不想被报告,则在这个方法前面加@SuperessWarnings(“deprecation”),现在javac在编译的时候就不会提示了。
@SuppressWarnings("deprecation")
public static void main(String[] args) {
// TODO Auto-generated method stub
System.runFinalizersOnExit(true);
}
这就是一个注解,告诉编译器某种标记信息。
一个注解就是一个类,用这个注解就相当于创建了这个类的一个实例对象。
@Depricated
直接在刚才的类中增加一个方法,并加上@Deprecated标注,在另外一个类中调用这个方法
一个以前写的方法现在不想用了,如果直接删除,其他用户可能会出错,这时就在这个方法前加@Deprecated注解,告诉别人这个方法过时了
@Deprecated
public static void sayHello() {
System.out.println("hi,itcast");
}
这时,别的类调用这个方法就会显示出这个类过时。
@Override
public boolean equals(Reflect other)方法与HashSet结合讲解
先提一下overload和override的区别
overload是重载,即父类有一个方法,子类重载这个方法是,方法名要相同,参数列表可变。集合在比较相等==的时候,如果子类写成equals(ReflectPoint obj)方法则该方法不会调用,因为参数不是Object,比较时时会调用父类的equals(Object obj)
而override是重写,即覆盖。方法名和参数列表都要一样。这样集合在比较相等==的才会调用子类的这个equals(Object obj)方法。
现在把ReflectPoint中的equals方法参数改为,public boolean equals(ReflectPoint obj),比较相等时是不会调用这个方法的。
这时在这个方法前加上@Override,则会提示错误,说这个不是override,你就会知道这个并不是覆盖了父类的equals方法,这样就可以把他改回来了。
总结:
注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素段上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
看java.lang包,可看到JDK中提供的最基本的annotation。
(jdk5的API中的java.lang包中,有一个类是Annotation Types 里面有三个基本的类:Deprecated, Override和SuppressWarnings)
二、注解的定义与反射调用
定义一个最简单的注解:public @interface MyAnnotation{}
把它加在某个类上:@MyAnnotation public class AnnotationTest{}
用反射进行测试AnnotationTest的定以上是否有@MyAnnotation
注解是一个特殊的类,如果你写一个类B想要应用到一个注解@A,前提是有人写好了一个注解类A:@interface A {},注解用@interface A这种格式定义。另一个类C想要调用这个类B,就要先检查这个类B是否用到了注解:
ClassC{
B.class.isAnnotationPresent(A.class);
A a = B.class.getAnnotation(A.class);
}
如上图。
实例:
在eclipse中可以直接new一个Annotation, 叫ItcastAnnotation:
public @interface ItcastAnnotation {}
在之前的AnnotationTest上可以用到这个注解:
@ItcastAnnotation
public class AnnotationTest {}
再写一个程序检查这个类是否应用了这个注解:
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
ItcastAnnotation annotation = (ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation);
}
根据发射测试的问题,引出@Reterntion元注解的讲解,其三种取值:RetentionPolicy.SOURCE, RetentionPolicy.CLASS, RetentionPolicy.RUNTIME;分别对应:java源文件-->class文件-->内存中的字节码
思考:@Override, @SuppressWarnings和@Deprecated这三个注解的属性值分别是什么?
@Override在SOURCE阶段,@SuppressWarnings在SOURCE阶段,@Desprecated在RUNTIME
屏幕却没有打印出来这个注解,这时在ItcastAnnotation这个注解类前加上@Retention(RetentionPolicy.RUNTIME)注解类前加的注解叫做元注解(还有元数据,元信息),屏幕上就可以打印出来注解了
当java源程序加了一个注解,这个源程序由javac编译成class可能会把源程序中的注解去掉。如果留的有,则程序用这个类的时候,class会被类加载器调进内存来,类加载器会对class进行处理,也有转换,class文件的注解也不一定保留下来。
所以一个注解的生命周期有三个阶段(源文件,class文件,内存中的字节码)
Retention可以声明这个注解的生命周期。默认值在class阶段。RetentionPolicy是一个枚举值,有三个值。
演示和讲解@ Target元注解
Target的默认值为任何元素,设置Target等于ElementType.METHOD,原来加在类上的注解就报错了,改为用数组方式设置(ElementType.METHOD, ElementType.TYPE)就可以了。
如果在ItcastAnnotation上面有@Target(ElementType.METHOD)这个注解,引用ItcastAnnotation注解的那个类中就只能在它的方法前注解ItcastAnnotation
解决办法:@Target({ElementType.METHOD, ElementType.TYPE})就可以了。因为Class这个类实现了Type接口,TYPE比Class更精准。type是jdk1.5出来的。
元注解以及其枚举属性值不用记,只要会看jdk提供那几个基本注解的API帮助文档的定义或其源代码,,按图索骥即可查到,或者直接看java.lang.annotation包下面的类。
三、为注解增加各种基本属性
什么是注解的属性
一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是这个机构的,否则,就不是。如果还想区分出是那个部门的,这时可以为胸牌增加一个属性来进行区分。加了属性的标记效果为:@MyAnnotation(collor=”red”)
定义基本类型的属性和应用属性:
在注解类中增加String color();
@MyAnnotation(color=”red”)
用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
MyAnnotation a = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.print(a.color());
可以认为上面这个@MyAnnotation是MyAnnotation类的一个实例对象
为属性指定缺省值:
String color() default “yellow”;
value属性:
String value() default “zxx”;
如果注解中有一个名称为value属性,且你只想设置value属性(即其他属性都采用默认值或者),那么就可以不写value=,只写value的值就行了。
四、为注解增加高级属性
数组类型的属性:
int[] arrayAttr() default{1,2,3};
@MyAnnotation(arrayAttr={2,3,4})
如果数组属性中只有一个元素,这时候属性值部分可以省略大括号
枚举类型的属性:
EnumTest.TrafficLights light();
@MyAnnotation(light = EnumTest.TrafficLight.GREEN)
注解类型的属性:
MetaAnnotation annotationAttr() default @MetaAnnotation(“xxxx”);
@MyAnnotation(annotationAttr=@MetaAnnotation(“yyy”))
可以认为上面这个@MyAnnotation是MyAnnotation类的一个实例对象,同样的道理,可以认为上面这个@MetaAnnotation是MetaAnnotation类的一个实例对象,调用代码如下:
MetaAnnotation ma = myAnnotation.annotationAttr();
System.out.println(ma.value());
注解的属性的返回值还是注解,而这个注解上又有属性
注解的详细语法可以通过看java语言规范了解,即看java的language specification。