Java注解

注解

注解是一种元数据,提供非程序本身的程序,注解不直接影响代码本身。

注解的用处:

  • 编译器的信息:注解用在编译器检测错误和取缔warning
  • 编译和部署的时候的处理:软件工具可以处理注释信息以生成代码,XML文件
  • 运行时处理:在运行时检查问题

注解的基础

注解用@向编译器指示后面的内容是注释。在以下例子,注解的名字是Override

1
2
@Override
void mySuperMethod() { ... }

注释可以包含可以命名或未命名的元素,并且这些元素有值:

1
2
@SuppressWarnings(value = "unchecked")
void myMethod() { ... }

如果注解有个叫value的值的话,可以省略这个值直接写,如下:

1
2
@SuppressWarnings("unchecked")
void myMethod() { ... }

如果注释没有元素,则可以省略括号,如前面的@Override示例所示。

也可以在同一声明中使用多个注释:

1
2
3
@Author(name = "Jane Doe")
@EBook
class MyClass { ... }

如果注释具有相同的类型,则称为重复注释:

1
2
3
@Author(name = "Jane Doe")
@Author(name = "John Smith")
class MyClass { ... }

从Java SE 8发行版开始,支持重复注释

声明注释类型

许多注释会替换代码中的注释。

假设传统上启动每个类提供重要信息的注释:

1
2
3
4
5
6
7
8
9
10
11
12
public class Generation3List extends Generation2List {

// Author: John Doe
// Date: 3/17/2002
// Current revision: 6
// Last modified: 4/12/2004
// By: Jane Doe
// Reviewers: Alice, Bill, Cindy

// class code goes here

}

要使用注释添加此相同元数据,必须先定义注释类型,语法是:

这里设置了注解的默认值default

1
2
3
4
5
6
7
8
@interface ClassPreamble {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
String[] reviewers();
}

就像interface的定义一样,只不过在前面增加了一个@,在定义了之后你就可以使用注解了

1
2
3
4
5
6
7
8
9
10
11
12
@ClassPreamble (
author = "John Doe",
date = "3/17/2002",
currentRevision = 6,
lastModified = "4/12/2004",
lastModifiedBy = "Jane Doe",
reviewers = {"Alice", "Bob", "Cindy"}
)
public class Generation3List extends Generation2List {


}

要使@ClassPreamble出现在java文档中,需要使用@Documented来表示。

1
2
3
4
5
6
7
8
import java.lang.annotation.*;

@Documented
@interface ClassPreamble {

// Annotation element definitions

}

预定义的注释类型

在JAVA SE中预定义了一种注解类型,Java编译器使用这种注解类型

他们分别是@Deprecated,@Override@SuppressWarnings

@Deprecated 注解表示已弃用标记的元素,不应再使用只要使用了编译器就会发出警告。

@Override注解表示编译器覆盖类的元素,虽然在重写方法时候不需要此批注,但是他有助于防止出错。如果标记的方法@Override无法正确的覆盖某个超类中的方法,则会编译器会出现错误

@SuppressWarnings注解告诉编译器不要生成相关的警告。在以下实例中,使用了不推荐使用的方法,编译器会发出警告,但是使用了这个注释,编译器就不会发出警告了

1
2
3
4
5
6
@SuppressWarnings("deprecation")
void useDeprecatedMethod() {

// - suppressed
objectOne.deprecatedMethod();
}

@SafeVarargs注解,当应用于方法或构造函数时,断言代码不对其varargs参数执行可能不安全的操作。使用此注释类型时,varargs将禁止与使用相关的未经检查的警告。

适用于其他注释的注释

  • @Retention注解指定标记注释的存储方式:

    • RetentionPolicy.SOURCE - 标记的注释仅保留在源级别中,并由编译器忽略。
    • RetentionPolicy.CLASS - 标记的注释在编译时由编译器保留,但Java虚拟机(JVM)会忽略。
    • RetentionPolicy.RUNTIME - 标记的注释由JVM保留,因此运行时环境可以使用它。
  • @Documented无论何时使用指定的注释,都应使用Javadoc工具记录这些元素。

  • @Target注释标记另一个注释,以限制可以应用注释的Java元素类型。也就是在什么地方注释。

    • ElementType.ANNOTATION_TYPE 可以应用于注释类型。
    • ElementType.CONSTRUCTOR 可以应用于构造函数。
    • ElementType.FIELD 可以应用于字段或属性。
    • ElementType.LOCAL_VARIABLE 可以应用于局部变量。
    • ElementType.METHOD 可以应用于方法级注释。
    • ElementType.PACKAGE 可以应用于包声明。
    • ElementType.PARAMETER 可以应用于方法的参数。
    • ElementType.TYPE 可以应用于类的任何元素。
  • @Inherited注释表明注释类型可以从超类继承。当用户查询注释类型并且该类没有此类型的注释时,将查询类的超类以获取注释类型。此注释仅适用于类声明。

类型注释和可插入类型系统

java SE 8之前,注释只能应用于声明,在java SE 8之后,注释可以用于任何类型的使用。这种注释称为类型注释,例如常见的@NonNull等。

一些tip

其实注解的定义很简单,就是@interface,然后配合@Target @Retention来说明注解的用在哪里,最后通过注解解释器,也就是反射,反射出注解以及其值下面给一个例子

1
2
3
4
5
6
7
@MyAnnotation(color="red")//应用MyAnnotation注解的color属性
public class MyAnnotationTest {
public static void main(String[] args) {
MyAnnotation annotation = (MyAnnotation)MyAnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(annotation.color());//输出red
}
}
谢谢您的鼓励~