什么是Java注解
注解又称标注,是加入代码的元数据。Java 5.0版本开始支持注解。
Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java虚拟机可以保留标注内容,在运行时可以获取到标注内容。 Java也支持自定义标注。
内置注解
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
作用在代码的注解是:
- @Override - 检查该方法是否是重载方法。如果发现其父类,或者引用的接口中没有该方法时,会报编译错误。
- @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
- @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
作用在其他注解的注解(又称元注解):
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件,还是在运行时可以通过反射访问。具体使用方式为:在注解类上添加@Retention(RetentionPolicy.SOURCE/CLASS/RUNTIME)。
- @Documented - 标记这些注解需要包含在 Java doc 中。
- @Target - 标记这个注解可以作用到哪些 Java 成员。如:这个注解需要作用于方法,则在注解类上添加@Target(ElementType.METHOD)。除了METHOD,其他成员有:CONSTRUCTOR(构造函数)、FIELD(成员变量,包括enum实例)、LOCAL_VARIABLE(局部变量)、PACKAGE(包)、TYPE(类、接口(包括注解类型)或enum声明)。如果需要作用在多个Java成员上,使用方式为:@Target( { ElementType.METHOD, ElementType.TYPE }) 。
- @Inherited - 标识添加了这个注解的类的子类自动继承这个注解。
从 Java 7 开始,额外添加了 3 个注解:
- @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
- @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。函数式接口 (Functional Interface) 就是一个具有一个方法的普通接口。可能有人会疑惑,函数式接口标记有什么用,这个原因是函数式接口可以很容易转换为 Lambda 表达式。
- @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。(元注解,使用方法)
注解应用实例
注解声明
// 声明Twizzle标注
public @interface Twizzle {
}
// @Twizzle标注toggle()方法。
@Twizzle
public void toggle() {
}
// 标注声明中可以用元注解说明使用方式、时间和对象
@Retention(RetentionPolicy.RUNTIME) // 该标注可以在运行时通过反射访问。
@Target({ElementType.METHOD}) // 该标注只用于类内方法。
public @interface Tweezable {
}
注解属性
注解可以看成是一种特殊的类,既然是类,那自然可以为类添加属性。语法为:类型 属性名();**
public @interface Edible {
boolean value() default false;
}
//等同于 @Edible(value = true)
//注解在只有一个元素且该元素的名称是value的情况下,可以省略“value=”。
@Edible(true)
Item item = new Carrot();
public @interface Author {
String first();
String last();
}
@Author(first = "Oompah", last = "Loompah")
Book book = new Book();
我们也可以为属性设置默认值,其语法为:类型 属性名() default 默认值;
注解与框架
**
标注通常用于软件框架,为用户定义的类和方法提供引用外部资源的情形,如XML配置文件、事务环境等。以下是一个标注过的EJB 3.0的类:
@Entity // 声明实体类
@Table(name = "people") // 映射该类到 "people"表
class Person implements Serializable {
@Id // 映射到主键
@GeneratedValue(strategy = GenerationType.AUTO) // 数据库自动生成键值
private Integer id;
@Column(length = 32) // 限长32个字符
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
以上代码中标注不执行任何特定行为,而是在运行时,为EJB容器获得足够的信息,生成对象到关系数据库的映射。
自定义注解和使用
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
String color();
}
@MyAnnotation(color="red")
public class MyAnnotationTest {
public static void main(String[] args) {
/**
* 用反射方式获得注解对应的实例对象后,在通过该对象调用属性对应的方法
*/
MyAnnotation annotation = MyAnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(annotation.color());
}
}
总结
在代码中添加注解就是打上了标记。我们可以通过反射来了解某个类及各种元素上有无何种标记,如果有,就去干相应的事。注解的应用结构图如下所示:
![注解.jpg](https://cdn.nlark.com/yuque/0/2019/jpeg/111066/1552307185878-da268c85-c8ed-4d0f-97cc-a5012e319a2c.jpeg#align=left&display=inline&height=247&name=%E6%B3%A8%E8%A7%A3.jpg&originHeight=347&originWidth=636&size=109238&status=done&width=452)
参考资料:维基百科 / Java注解基本原理 / Java基础-注解 / 秒懂注解