java注解解析
什么是注解
什么是注解,注解就是一种描述源码的元数据。我们可以通过注解给类、方法或字段提供额外的信息以便了解更多信息。
举个例子,java中常见的@Override
就是一个注解。它的作用是提示由它修饰的方法是一个重写方法,如果父类没有这个方法编译器会报错。这样这个注解就给我们传达了重写方法
这个信息,在使用时就会多加注意。
@Override
public String toString(){
return "this is my string implements";
}
又如,在Spring体系中使用的注解,如Service
、Controller
等,告知Spring这是一个bean,并进行相应处理。
怎样自定义注解
了解了注解的含义和用途,下面就该编写自己的注解了。
在深入之前,先要知道4种元注解,这4种注解用于定义修饰其他注解。
@Target
描述注解用于哪里,如类、方法或是字段。@Retention
指明注解的声明周期@Documented
注解是否包含在javaDoc中@Inherited
是否允许子类继承该注解
@Documented
和@Inherited
好理解一些,下面我们看看前两个注解:
@Target
表明该注解是用于修饰类还是方法或字段。取值是一个ElementType枚举类。主要有以下值:
ElementType.TYPE //描述类、接口或enum声明
ElementType.FIELD //描述实例变量
ElementType.METHOD //方法
ElementType.PARAMETER //参数
ElementType.CONSTRUCTOR //构造函数
ElementType.LOCAL_VARIABLE //本地变量
ElementType.ANNOTATION_TYPE //另一个注释
ElementType.PACKAGE //用于记录java文件的package信息
@Retention
定义该注解信息在什么期间有效,取值为RetentionPolicy枚举类,共有3个值:
RetentionPolicy.SOURCE
在编译期就丢弃,仅存在于源码中。如@Override
等就属于此类RetentionPolicy.CLASS
在类加载期丢弃,即注解将存在于字节码中。默认注解为此类型。RetentionPolicy.RUNTIME
注解信息一直保留,不会丢弃。这意味着可以反射获取到注解信息。一般自定义注解大都使用此方式。
注解定义
注解使用以下@interface
关键字定义:如定义一个名为DAO的注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DAO {
}
由上可知,该@DAO
用于修饰类、接口或枚举类,注解信息一直存在不会擦除。
下面再自定义一个名为Hello
注解,用于修饰方法,可生产在javaDoc中,可通过反射拿到信息的注解。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Hello {
String value() default "Hi !";
}
上面注解体内添加了value方法。并指定了默认值。表明该注解的一个属性,使用时可以这样:
@Hello(value = "world")
public String hello() {
return "hello";
}
当然也可在注解内添加多个方法,对应使用时的多个属性。这里就不提了。
让注解起作用
看过前面的定义和使用,你可能会疑惑,我没有定义任何逻辑,注解怎么起作用啊?是啊,我们知道,@Override
是java的注解,它靠编译期检查父类方法就能实现,而我们自定义的注解怎么办呢?
事实上,定义注解只是编写注解的第一步。我们需要在合适的时机给她赋予逻辑。还记得前面提过,自定义的注解大都是RetentionPolicy.RUNTIME
类型的。这是为了在反射时取得注解信息。下面是一个小例子。
public class TestAnno {
@Hello(value = "world")
public String hello() {
return "hello";
}
public void callHello() {
try {
TestAnno testAnno = new TestAnno();
Method method = testAnno.getClass().getMethod("hello", null);
Hello todo = method.getAnnotation(Hello.class); //获取注解信息
String str = method.invoke(testAnno, null).toString();
System.out.println(str + "," +todo.value() ); //将注解信息用在方法中
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
TestAnno testAnno = new TestAnno();
testAnno.callHello();
}
}
打印结果 :
hello,world
以上只是一个小小的例子,并没有使用价值。但能说明可以在运行时获取注解信息并在方法运行时相结合。其他地方也是用了反射,大同小异。