注解
注解目的
- 生成文档 ,如 @see @param @return 等
- 跟踪代码依赖性,实现替代配置文件功能
- 在编译时进行格式检查。如@override
注解基础
最基础的注解如下
@Entity
@ 表示这是一个注解,之后的字母表示这个注解的名字,以上例子的注解名字为 Entity
注解元素
Java 注解中有一些元素,并且可以设置他们的值,举个🌰
@Entity(tableName = "vehicles")
注解Entity
中含有一个tableName
元素,并且把这个元素赋值为vehicles。
一个注解也可以同时含有多个元素
@Entity(tableName = "vehicles", primaryKey = "id")
当一个注解只含有一个元素时,赋值可以写成以下形式
@InsertNew("yes")
注解的种类
注解可以修饰 类、接口、方法、参数、域、本地变量。
@Entity
public class Vehicle {
@Persistent
protected String vehicleName = null;
@Getter
public String getVehicleName() {
return this.vehicleName;
}
public void setVehicleName(@Optional vehicleName) {
this.vehicleName = vehicleName;
}
public List addVehicleNameToList(List names) {
@Optional
List localNames = names;
if(localNames == null) {
localNames = new ArrayList();
}
localNames.add(getVehicleName());
return localNames;
}
}
Java 内置的注解
Java 内置了三种指导编译的注解,分别为
- @Deprecated
- @Override
- @SuppressWarnings
@Deprecated
Annotation type used to mark program elements that should no longer be used by programmers. Compilers produce a warning if a deprecated program element is used.
可以修饰 类、方法、域。表示之后不会被使用了。如果代码中使用到了注解为@Deprecated 的代码,编译器会产生警告
@Override
Annotation type used to mark methods that override a method declaration in a superclass. Compilers produce an error if a method annotated with @Override does not actually override a method in a superclass.
修饰方法,表示此方法复现了父类的方法,如果在父类中没有相应的方法编译器会报错
@Override 并不是必须的,但是在子类中复写父类的方法中最好使用,以防复写的时候名字和父类的方法名不一致而产生一些问题
public class MySuperClass {
public void doTheThing() {
System.out.println("Do the thing");
}
}
public class MySubClass extends MySuperClass{
@Override
public void doTheThing() {
System.out.println("Do it differently");
}
}
@SuppressWarnings
Annotation type used to indicate that the compiler should not issue the specified warnings for the marked program element. Warnings are not only suppressed for the annotated element but also for all program elements contained in that element.
It is recommended that programmers always use this annotation on the most deeply nested element where it is actually needed.
使编译器不产生对此方法的警告信息。
自定义注解
注解的定义和类、接口的定义类似。举个🌰
@interface MyAnnotation {
String value();
String name();
int age();
String[] newNames();
}
使用 @interface 关键字表示定义的是一个注解。其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型。,元素只支持原始的数据类型。
使用上述的注解
@MyAnnotation(
value="123",
name="Jakob",
age=37,
newNames={"Jenkov", "Peterson"}
)
public class MyClass {
}
元素默认值
在定义注解时可以设置默认值,举个🌰
@interface MyAnnotation {
String value() default "";
String name();
int age();
String[] newNames();
}
元素value
在使用时可以不赋值,当不赋值时,默认采用定义时的默认值
@MyAnnotation(
name="Jakob",
age=37,
newNames={"Jenkov", "Peterson"}
)
public class MyClass {
}
@Retention
- 用来声明注解的保留策略,有CLASS、RUNTIME和SOURCE这三种,分别表示注解保存在类文件、JVM运行时刻和源代码中。
- 只有当声明为RUNTIME的时候,才能够在运行时刻通过反射API来获取到注解的信息。
- RetentionPolicy.SOURCE 注解将被编译器丢弃
- RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃
- RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String value() default "";
}
使用时可以使用反射的方法得到注解中的信息
反射得到注解信息
类注解
@MyAnnotation(name="someName", value = "Hello World")
public class TheClass {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
public String name();
public String value();
}
//法1:可以直接得到所有的注解,在里面寻找MyAnnotation
Class aClass = TheClass.class;
Annotation[] annotations = aClass.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
//法2:可以直接得到MyAnnotation注解
Class aClass = TheClass.class;
Annotation annotation = aClass.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
方法注解
public class TheClass {
@MyAnnotation(name="someName", value = "Hello World")
public void doSomething(){}
}
Method method = ... //obtain method object
Annotation[] annotations = method.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
//同样
Method method = ... // obtain method object
Annotation annotation = method.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
域、参数注解同理
@Target
用来声明注解可以被添加在哪些类型的元素上,如类型、方法和域等。
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
public @interface MyAnnotation {
String value();
}
🌰表示这个注解只能修饰方法
表示该注解用于什么地方,可能的值在枚举类 ElemenetType 中,包括:
- ElemenetType.CONSTRUCTOR 构造器声明
- ElemenetType.FIELD 域声明(包括 enum 实例)
- ElemenetType.LOCAL_VARIABLE 局部变量声明
- ElemenetType.METHOD 方法声明
- ElemenetType.PACKAGE 包声明
- ElemenetType.PARAMETER 参数声明
- ElemenetType.TYPE 类,接口(包括注解类型)或enum声明
@Inherited
允许子类继承父类中的注解,举个🌰
java.lang.annotation.Inherited
@Inherited
public @interface MyAnnotation {
}
@MyAnnotation
public class MySuperClass { ... }
public class MySubClass extends MySuperClass {... }
在这个例子中,因为MySubClass
继承了MySuperClass
,并且MySuperClass
被注解@MyAnnotation
修饰了,所以类MySubClass
继承了@MyAnnotation
注解
@Documented
@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。
举个🌰
import java.lang.annotation.Documented;
@Documented
public @interface MyAnnotation {
}
@MyAnnotation
public class MySuperClass { ... }
参考
http://blog.csdn.net/tigerdsh/article/details/8848890
http://tutorials.jenkov.com/java/annotations.html