从JDK5开始,Java增加了对元数据的支持,也就是Annotation,它也被称作注释。
基本的Annotation:
限定重写父类方法:@Override
@Override就是用来指定方法的重写,它强制一个子类必须覆盖父类的方法,这个大家比较熟悉就不多说了。
已过时的标记:@Deprecated
如果你的程序元素被标记成Deprecated的话,那么你在调用的时候该程序元素就会被加线,证明该方法过时,不建议被使用。
public class TestDeprecate {
@Deprecated
public void sayHello() {
System.out.println("Hello");
}
public void sayWorld() {
sayHello();
}
}
抑制编译器的警告:@SuppressWarnings
如果你想取消显示指定的编译器警告的话,就可以用该Annotation,最常见的是在泛型上,下面就举这个例子:
@SuppressWarnings(value="unchecked")
public class TestSuppressWarnings {
public static void main(String[] args) {
List<String> list = new ArrayList();
}
}
这样就取消了没有使用泛型的警告。
自定义Annotation:
定义一个新的Annotation类型要使用@interface关键字,下面就是一个简单的Annotation类型:
public @interface Hello {
}
当然自定义的Annotation还可以带成员变量,它的成员变量在Annotation定义一无形参的方法形式来声明的,其方法名和返回值定义了该成员变量的名字和类型:
public @interface Hello {
String name();
int age();
}
简单的实际应用:
public class World {
@Hello(name="guo", age=20)
public void say() {
System.out.println("World");
}
}
通过简单的key=value形式就给成员变量赋值了
当然自定义的Annotation的成员变量可以设定默认值:
public @interface Hello {
String name() default "guo";
int age() default 20;
}
提取Annotation信息:
被Annotation修饰的程序元素我们可以根据Annotation提取出里面的信息:
下面先介绍=几个方法:
getAnnotation(Class<T> annltationClass):返回该程度元素上存在的指定类型的注释,如果该类的注释不存在就返回null
Annotation[] getAnnotations():返回该程序元素上存在的所有注释
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断该程序上元素上是否存在指定类型的注释,如果存在即true,否则false
下面我们用反射的知识去帮助提取出相应的信息:
public class World {
@Hello(name="guo", age=20)
public void say() {
System.out.println("World");
}
public static void main(String[] args) {
try {
Annotation[] annotation = Class.forName("com.xujianguo.annotation.World").getMethod("say").getAnnotations();
for(Annotation a : annotation) {
System.out.println(a.toString());
if(a instanceof Hello) {
System.out.println("-------------------");
System.out.println(((Hello)a).name());
System.out.println(((Hello)a).age());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
这里要严重提醒的是:如果要用反射就拿Annotation的信息的话,就可以在定义的Annotation上加上@Retention:
@Retention(value=RetentionPolicy.RUNTIME)
public @interface Hello {
String name() default "guo";
int age() default 20;
}
这样保证了在JVM会保留该Annotation,就可以通过反射获取信息了。
先面模拟一下Junit的单元测试:
定义@TestSimulation这个新的Annotation:
@Retention(value=RetentionPolicy.RUNTIME)
public @interface TestSimulation {
}
在Communication类中应用@TestSimulation:
public class Communication {
@TestSimulation
public void say() {
System.out.println("hello");
}
public void call() {
System.out.println("call you");
}
@TestSimulation
public void look() {
System.out.println("look");
}
}
定义工具类解析:
public class AnnotationUtil {
public static void processAnnotation(String path) {
try {
Class clazz = Class.forName(path);
Object o = clazz.newInstance();
Method[] methods = clazz.getMethods();
for(Method m : methods) {
if(m.isAnnotationPresent(TestSimulation.class)) {
m.invoke(o);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试类:
public class StartUp {
public static void main(String[] args) {
AnnotationUtil.processAnnotation("com.xujianguo.annotation.Communication");
}
}
测试结果:
hello
look