一、什么是注解
Java 注解(Annotation)又称为 Java 标注,是 Java5开始支持加入源代码的特殊语法元数据。Java 语言中的类、方法、变量、参数和包等都可以被标注。Java 标注可以通过反射获取标注的内容。在编译器生成class文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容。
回顾以往学习的内容,我们学习继承时,子类若重写了父类的方法,可以在子类重写的方法上使用@Override注解:
将@Override 注解标注在子类重写的方法上,可检查该方法是否正确地重写了父类的方法,如有错误将会编译报错。
二、注解的作用
注解与注释:
注解:告诉编译器如何运行程序!
注释: 给程序员阅读,对编译、运行没有影响;
注解作用
1. 告诉编译器如何运行程序;
2. 简化(取代)配置文件
// 重写父类的方法
@Override
public String toString() {
return super.toString();
}
// 标记方法以及过时
@Deprecated
private void save1() {
}
用在代码中的注解
- @Override:检查该方法是否正确地重写了父类的方法。如果重写错误,会报编译错误;
- @Deprecated:标记过时方法。如果使用该方法,会报编译警告;
- @SuppressWarnings:指示编译器去忽略注解中声明的警告;
- @SafeVarargs:Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告;
- @FunctionalInterface:Java 8 开始支持,标识一个匿名函数或函数式接口。
三、自定义注解
通过自定义注解,可以给类、字段、方法上添加描述信息!
1、元注解
元注解: 表示注解的注解!
①指定注解的可用范围:
@Target({
TYPE, 类
FIELD, 字段
METHOD, 方法
PARAMETER, 参数
CONSTRUCTOR, 构造器
LOCAL_VARIABLE 局部变量
})
②指定注解的生命周期
@Retention(RetentionPolicy.SOURCE) 注解只在源码级别有效
@Retention(RetentionPolicy.CLASS) 注解在字节码即别有效 默认值
@Retention(RetentionPolicy.RUNTIME) 注解在运行时期有效
③常见元注解
- @Retention:标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问;
- @Documented:标记这些注解是否包含在用户文档中;
- @Target:标记这个注解应该是哪种 Java 成员;
- @Inherited:标记这个注解是继承于哪个注解类;
- @Repeatable:Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
2、自定义
- 创建注解;
- 定义注解的参数和默认值;
- 用元注解配置注解。
①创建注解
注解通过@interface关键字来定义。
注意:通过 @interface 关键字定义注解,通过关键字 interface定义接口。注意两者不要混淆。创建注解时选择的是Annotation
public @interface Author {
}
②定义注解的参数和默认值
public @interface Author {
String name() default "";
//带默认值的属性,使用时候不给这个属性赋值,也有一个默认值
int age() default 20;
//如果使用注解里面的value属性,使用的时候可以省略.
//前提是:注解中只有这一个属性时候
String[] value() default {};
}
③用元注解配置注释
//表示这个注解可以作用到方法、属性、类上
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
String name() default "";
//带默认值的属性,使用时候不给这个属性赋值,也有一个默认值
int age() default 20;
//如果使用注解里面的value属性,使用的时候可以省略.
//前提是:注解中只有这一个属性时候
String[] value() default {};
}
@Retention | RetentionPolicy.SOURCE | 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视; |
RetentionPolicy.CLASS | 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中; | |
RetentionPolicy.RUNTIME | 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。 | |
@Target | ElementType.ANNOTATION_TYPE | 可以给一个注解进行注解; |
ElementType.CONSTRUCTOR | 可以给构造方法进行注解 | |
ElementType.FIELD | 可以给属性进行注解; | |
ElementType.LOCAL_VARIABLE | 可以给局部变量进行注解; | |
ElementType.METHOD | 可以给方法进行注解; | |
ElementType.PACKAGE | 可以给一个包进行注解; | |
ElementType.PARAMETER | 可以给一个方法内的参数进行注解; | |
ElementType.TYPE | 可以给一个类型进行注解,比如类、接口、枚举。 |
④应用
//@Author("男")
//@Author(value = "男")
//@Author(value = {"男", "女"})
@Author(name = "zhao", age = 12, value = "男")
public class AuthorDemo {
@Author
private String str;
@Author(name = "zhangsan", age = 23, value = {"男", "女"})
//@Author(name = "zhangsan")
public void add() {
}
@Test
public void test1() throws NoSuchMethodException {
Class<AuthorDemo> clazz = AuthorDemo.class;
Author typeAuthor = clazz.getAnnotation(Author.class);
System.out.println(typeAuthor.value()[0]);
//1.先获得代表这个方法的Method
Method method = clazz.getDeclaredMethod("add");
//2.在Method上拿到指定注解
Author methodAnnotation = method.getAnnotation(Author.class);
System.out.println(methodAnnotation.name());//zhangsan
System.out.println(methodAnnotation.age());//23
System.out.println(Arrays.toString(methodAnnotation.value()));//[男, 女]
}
}