Java 注解(Annotation)
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。
格式
public @interface 注解名称{
属性列表;
}
分类
大致分为三类:
- 自定义注解
自定义注解就是我们自己写的注解 - JDK内置注解
比如@Override检验方法重写 - 第三方框架提供的注解
第三方框架定义的注解比如SpringMVC的@Controller等
作用
如果说注释是写给人看的,那么注解就是写给程序看的。它更像一个标签,贴在一个类、一个方法或者字段上。它的目的是为当前读取该注解的程序提供判断依据及少量附加信息。比如程序只要读到加了@Test的方法,就知道该方法是待测试方法,又比如@Before注解,程序看到这个注解,就知道该方法要放在@Test方法之前执行。有时我们还可以通过注解属性,为将来读取这个注解的程序提供必要的附加信息,比如@RequestMapping("/user/info")提供了Controller某个接口的URL路径。
注解的本质
1.创建一个java程序
2.编译生成字节码文件
3.反编译MyAnnotation.java
我们发现,@interface变成了interface,而且自动继承了Annotation:
接口中所有属性都是pubic static final修饰的,方法都是public abstract修饰的
由于接口默认方法的修饰符就是public abstract,所以可以省略,直接写成:
反射获取注解信息:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
//@Retention(注解的保留策略)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String getMsg() default "none";
}
保留策略”这个元注解的意义在哪呢?
“一般来说,普通开发者使用注解的时机都是运行时,比如反射读取注解(也有类似Lombok这类编译期注解)。既然反射是运行时调用,那就要求注解的信息必须保留到虚拟机将.class文件加载到内存为止。如果你需要反射读取注解,却把保留策略设置为RetentionPolicy.SOURCE、RetentionPolicy.CLASS,那就读取不到了。
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@MyAnnotation(getMsg = "this is a class")
public class TestAnnotation {
@MyAnnotation(getMsg = "this is a field")
public String name;
@MyAnnotation(getMsg = "this is a method")
public void getName() {}
@MyAnnotation()//默认值
public void getAge() {}
public static void main(String[] args) throws Exception {
Class c = Class.forName("TestAnnotation");
// 获取类上的注解
MyAnnotation annotationOnClass = (MyAnnotation) c.getAnnotation(MyAnnotation.class);
System.out.println(annotationOnClass.getMsg());
// 获取成员变量上的注解
Field name = c.getField("name");
MyAnnotation annotationOnField = name.getAnnotation(MyAnnotation.class);
System.out.println(annotationOnField.getMsg());
// 获取hello方法上的注解
Method hello = c.getMethod("getName");
MyAnnotation annotationOnMethod = hello.getAnnotation(MyAnnotation.class);
System.out.println(annotationOnMethod.getMsg());
// 获取defaultMethod方法上的注解
Method defaultMethod = c.getMethod("getAge");
MyAnnotation annotationOnDefaultMethod = defaultMethod.getAnnotation(MyAnnotation.class);
System.out.println(annotationOnDefaultMethod.getMsg());
}
}
内置的注解
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
作用在代码的注解是
- @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
- @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
作用在其他注解的注解(或者说 元注解)是:
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @Inherited - 标记这个注解是继承于哪个注解类(默认注解并没有继承于任何子类)
从 Java 7 开始,额外添加了 3 个注解: - @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
- @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
- @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。