4、注解
1、自定义注解
特殊属性:value 属性
- 如果只有一个 value 属性的情况下,使用 value 属性的时候可以省略 value 名称不写
- 但是如果有多个属性,且多个属性没有默认值,那么 value 名称是不能省略的
属性的数据类型
- 八种基本数据类型:byte、short、int、long、float、double、boolean、char
- String、Class、注解类型、枚举类
- 以上类型的一维数组形式
public @interface 注解名称 {
public 属性类型 属性名() default 默认值; // 默认值可以不写
}
// 注解使用
public @interface MyAnnotation {
public String name();
}
@MyAnnotation(name = "张三")
// 注解使用, key 的名称是 value, key 可以省略不写
public @interface MyAnnotation {
public String value();
}
@MyAnnotation("张三")
2、元注解
元注解:就是注解的注解
- @Target:约束自定义注解只能在哪些地方使用,也就是说给谁添加注解
- @Retention:声明注解的生命周期
- @Documented:是否在文档注释中体现
- @Inherited:是否可以被继承到所标记的类的子类
- @Repeatable:是否可以重复使用
2.1、@Target
@Target 中可使用的值定义在 ElementType 枚举类中,常用值如下
- TYPE:类、接口(包括注解)、枚举
- FIELD:成员变量(属性)
- METHOD:成员方法
- PARAMETER:方法参数
- CONSTRUCTOR:构造器
- LOCAL_VARIABLE:局部变量
- PACKAGE:包
- ANNOTATION_TYPE:注解
- TYPE_PARAMETER:能在类型变量的声明语句中(泛型)
- TYPE_USE:能在使用类型的任何语句中
2.2、@Retention
@Retention 中可使用的值定义在 RetentionPolicy 枚举类中,常用值如下
- RetentionPolicy.SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
- RetentionPolicy.CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,不会被加载到 JVM 中,默认值
- RetentionPolicy.RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)
@Retention | 源码阶段 | 字节码文件阶段 | 运行阶段 |
---|---|---|---|
SOURCE | ✓ | × | × |
CLASS | ✓ | ✓ | × |
RUNTIME | ✓ | ✓ | ✓ |
2.3、@Documented
@Documented
使用 Javadoc 工具可以从程序源代码中抽取类、方法、成员等注释形成一个和源代码配套的 API 帮助文档,而该工具抽取时默认不包括注解内容
- 被它修饰的注解将被 Javadoc 工具提取成文档
- 定义为 @Documented 的注解必须设置 @Retention(RetentionPolicy.RUNTIME)
2.4、@Inherited
@Inherited 是否可以被继承到所标记的类的子类
如果一个超类被该注解标记过的注解进行注解时,如果子类没有被任何注解应用时,该子类就继承超类的注解
2.5、@Repeatable
@Repeatable 是否可以重复使用,在一个地方使用多次相同的注解
// 注解类
@Repeatable(value = ManTypes.class)
public @interface ManType {
String value() default "";
}
// 注解容器类
public @interface ManTypes {
ManType[] value();
}
// @ManTypes({@ManType("歌手"), @ManType("超人")})
@ManType(value = "歌手")
@ManType(value = "超人")
public class Test {
}
3、注解解析
注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容
解析注解的技巧:注解在哪个成分上,我们就先拿哪个成分对象
- 作用在类上,则要该类的 Class 对象,再来拿上面的注解
- 作用方法,则要获得该方法对应的 Method 对象,再来拿上面的注解
- 作用在变量上,则要获得该成员变量对应的 Field 对象,再来拿上面的注解
与注解解析相关的接口
- Annotation:注解的顶级接口,注解都是 Annotation 类型的对象
- AnnotatedElement:该接口定义了与注解解析相关的解析方法
所有的类成分 Class、Method、Field、Constructor,都实现了 AnnotatedElement 接口,它们都拥有解析注解的能力
方法 | 说明 |
---|---|
boolean isAnnotationPresent(Class<Annotation> annotationClass) | 判断当前对象是否使用了指定的注解,如果使用了则返回 true,否则 false |
T getDeclaredAnnotation(Class<T> annotationClass) | 根据注解类型获得对应注解对象 |
Annotation[] getDeclaredAnnotations() | 获得当前对象上使用的所有注解,返回注解数组 |
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
String value();
double price() default 100;
String[] author();
}
@Book(value = "《情深深雨濛濛》", price = 99.9, author = {"琼瑶", "dlei"})
public class BookStore {
@Book(value = "《三少爷的剑》", price = 399.9, author = {"古龙", "熊耀华"})
public void test() {}
}
public class Test {
@Test
public void parseClass() {
Class c = BookStore.class; // 先得到类对象
// 判断这个类上面是否存在这个注解
if(c.isAnnotationPresent(Book.class)) {
Book book = (Book) c.getDeclaredAnnotation(Book.class); // 直接获取该注解对象
System.out.println(book.value());
System.out.println(book.price());
System.out.println(Arrays.toString(book.author()));
}
}
@Test
public void parseMethod() throws NoSuchMethodException {
Class c = BookStore.class; // 先得到类对象
Method m = c.getDeclaredMethod("test"); // 再得到方法对象
// 判断这个类上面是否存在这个注解
if(m.isAnnotationPresent(Book.class)) {
Book book = (Book) m.getDeclaredAnnotation(Book.class); // 直接获取该注解对象
System.out.println(book.value());
System.out.println(book.price());
System.out.println(Arrays.toString(book.author()));
}
}
}
4、有注解就执行
public class Test {
public void test1(){
System.out.println("test1");
}
@MyTest
public void test2(){
System.out.println("test2");
}
@MyTest
public void test3(){
System.out.println("test3");
}
// 启动菜单: 有注解的才被调用
public static void main(String[] args) throws Exception {
Test t = new Test();
Class c = Test.class; // 获取类对象
Method[] methods = c.getDeclaredMethods(); // 提取全部方法
// 遍历方法, 看是否有 MyTest 注解, 有就跑它
for (Method method : methods) {
if(method.isAnnotationPresent(MyTest.class)){
method.invoke(t); // 跑它
}
}
}
}
5、预制注解
预制注解就是 Java 语言自身提供的注解
注解 | 说明 |
---|---|
@auther | 标明开发该类模块的作者,多个作者之间使用 , 分割 |
@version | 标明该类模块的版本 |
@see | 参考转向,也就是相关主题 |
@since | 从哪个版本开始增加的 |
@param | 对方法中某参数的说明,如果没有参数就不能写 |
@return | 对方法返回值的说明,如果方法的返回值类型是 void 就不能写 |
@execption | 对方法可能抛出的异常进行说明 |
@Override | 限定重写父类方法,该注解只能用于方法 |
@Deprecated | 用于表示所修饰的元素(类、方法等)已过时 |
@SuppressWarnings | 抑制编译器警告 |
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17472249.html