注解其实就是代码里的特殊标记,必须搭配注解的信息处理流程才有意义(使用反射)。
这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。
注解可以修饰:包、类、构造器、成员变量、方法、参数、局部变量 的声明。
这些信息被保存在注解的 “name=value” 对中。
常用的注解
生成文档相关的注解
@author:标明开发该类模块的作者,多个作者之间使用 ,分割
@version:标明该类模块的版本
@see:参考转向,也就是相关主题
@since:从哪个版本开始增加的
@param:对方法中参数的说明
@return:对方法返回值的说明
@exception:对方法可能抛出的异常进行说明
其中 @param @return @exception 这三个注解只能用于方法
在编译时进行格式检查的注解 也是 JDK 内置的三个注解
@Override:只用于重写父类方法
@Deprecated:用于表示所修饰的元素(类,方法、属性)已过时,不建议使用,但是还能调用
@SuppressWarnings:抑制编译器警告
@Test
public void Test() {
// 如果 a 没有被使用,则会有一个警告,但不影响运行
// 如果 a 没有被使用,加上该注解后,警告消失
@SuppressWarnings("unused")
int a = 10;
}
自定义注解
JDK 中的元注解
@Target:用于指定修饰元素的类型(类、构造器、局部变量 等)
@Retention:用于指定注解的生命周期
- source:编译后,注解将会被丢弃,即 class 文件中无该注解
- class:编译后,注解将被保留在 class 文件中,但运行 Java 程序时,JVM 不保留注解
- runtime:编译后,注解将被保留在 class 文件中,并且运行 Java 程序时,JVM 保留注解
- 如果不写,class 属性是生命周期的默认值
@Document:默认情况,JavaDoc 不包含注解,如果注解被 @Document 修饰,则注解被 JavaDoc 提取成文档
@Inherited:被 @Inherited 修饰的注解具有继承性。默认不具有继承性。
元注解用于修饰其他注解。
注解用 @interface 声明。
注解 默认继承 java.lang.annotation.Annotation 接口。
注解的成员变量,以无参方法的形式声明。
如果成员变量只有一个 value 变量,则使用时,value 可省略不写。
可以用 default 关键字为注解的成员变量指定初始值。
public @interface LoginRequired {
boolean value() default true;
}
Java8 对元注解的增强
可重复注解
可重复注解,即注解可以重复定义多个。
两个注解的 Target、Retention、Inherited 等元注解 必须相同
@MyAnnotation(value="hi")
@MyAnnotation(value="abc")
class Person{
private String name;
private int age;
public Person() {
}
}
@Repeatable(MyAnnotations.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
public @interface MyAnnotation {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
public @interface MyAnnotations {
MyAnnotation[] value();
}
在 JDK8 之前,注解只能在声明上使用,
在 JDK8 及之后,注解可以写在任何使用类型的地方。
JDK8 的元注解 @Target 的参数类型 ElementType 枚举值多了两个:TYPE_PARAMETER、TYPE_USE
@Target(value = {
ElementType.TYPE_PARAMETER
})
@Retention(RetentionPolicy.RUNTIME)
@interface Ann7 {
String value() default "";
}
public class UseAnnotation7<@Ann7() T0, @Ann7() T1> {
public <@Ann7() T2> void m1() {
}
public static void main(String[] args) throws NoSuchMethodException {
for (TypeVariable typeVariable : UseAnnotation7.class.getTypeParameters()) {
print(typeVariable);
}
for (TypeVariable typeVariable : UseAnnotation7.class.getDeclaredMethod("m1").getTypeParameters()) {
print(typeVariable);
}
}
private static void print(TypeVariable typeVariable) {
System.out.println("类型变量名称:" + typeVariable.getName());
Arrays.stream(typeVariable.getAnnotations()).forEach(System.out::println);
}
}
类型变量名称:T0
@com.javacode2018.lesson001.demo18.Ann7(value="")
类型变量名称:T1
@com.javacode2018.lesson001.demo18.Ann7(value="")
类型变量名称:T2
@com.javacode2018.lesson001.demo18.Ann7(value="")
public enum ElementType {
/* 类、接口、枚举、注解上面 */
TYPE,
/* 字段上 */
FIELD,
/* 方法上 */
METHOD,
/* 方法的入参上 */
PARAMETER,
/* 构造函数上 */
CONSTRUCTOR,
/* 局部变量上 */
LOCAL_VARIABLE,
/* 注解上 */
ANNOTATION_TYPE,
/* 包上 */
PACKAGE,
/* 类型参数上(类型变量) */
TYPE_PARAMETER,
/* 类型名称上,即任何使用类型的地方 */
TYPE_USE
}