什么是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 开始支持,标识某注解可以在同一个声明上使用多次。(元注解,使用方法

注解应用实例

注解声明

  1. // 声明Twizzle标注
  2. public @interface Twizzle {
  3. }
  4. // @Twizzle标注toggle()方法。
  5. @Twizzle
  6. public void toggle() {
  7. }
  8. // 标注声明中可以用元注解说明使用方式、时间和对象
  9. @Retention(RetentionPolicy.RUNTIME) // 该标注可以在运行时通过反射访问。
  10. @Target({ElementType.METHOD}) // 该标注只用于类内方法。
  11. public @interface Tweezable {
  12. }

注解属性

注解可以看成是一种特殊的类,既然是类,那自然可以为类添加属性。语法为:
类型 属性名();**

  1. public @interface Edible {
  2. boolean value() default false;
  3. }
  4. //等同于 @Edible(value = true)
  5. //注解在只有一个元素且该元素的名称是value的情况下,可以省略“value=”。
  6. @Edible(true)
  7. Item item = new Carrot();
  8. public @interface Author {
  9. String first();
  10. String last();
  11. }
  12. @Author(first = "Oompah", last = "Loompah")
  13. Book book = new Book();

我们也可以为属性设置默认值,其语法为:类型 属性名() default 默认值;

注解与框架
**
标注通常用于软件框架,为用户定义的类和方法提供引用外部资源的情形,如XML配置文件、事务环境等。以下是一个标注过的EJB 3.0的类:

  1. @Entity // 声明实体类
  2. @Table(name = "people") // 映射该类到 "people"表
  3. class Person implements Serializable {
  4. @Id // 映射到主键
  5. @GeneratedValue(strategy = GenerationType.AUTO) // 数据库自动生成键值
  6. private Integer id;
  7. @Column(length = 32) // 限长32个字符
  8. private String name;
  9. public Integer getId() {
  10. return id;
  11. }
  12. public void setId(Integer id) {
  13. this.id = id;
  14. }
  15. public String getName() {
  16. return name;
  17. }
  18. public void setName(String name) {
  19. this.name = name;
  20. }
  21. }

以上代码中标注不执行任何特定行为,而是在运行时,为EJB容器获得足够的信息,生成对象到关系数据库的映射。

自定义注解和使用

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target( { ElementType.METHOD, ElementType.TYPE })
  3. public @interface MyAnnotation {
  4. String color();
  5. }
  6. @MyAnnotation(color="red")
  7. public class MyAnnotationTest {
  8. public static void main(String[] args) {
  9. /**
  10. * 用反射方式获得注解对应的实例对象后,在通过该对象调用属性对应的方法
  11. */
  12. MyAnnotation annotation = MyAnnotationTest.class.getAnnotation(MyAnnotation.class);
  13. System.out.println(annotation.color());
  14. }
  15. }

总结

  1. 在代码中添加注解就是打上了标记。我们可以通过反射来了解某个类及各种元素上有无何种标记,如果有,就去干相应的事。注解的应用结构图如下所示:
  2. ![注解.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基础-注解 / 秒懂注解