第 18 章 – Java 注解 – 总结
第 18 章 – 注解 – 总结
使用注解流程: 1 定义注解 2 定义注解处理器 3 使用注解
1.什么是注解
方法前面使用@Override就是一个注解,表示被注解的方法必须要覆盖基类中的一个方法.
@Deprecated注解表示API中的方法等是已经废弃的,程序中使用了废弃的方法会获得一个警告.
@SuppresWarnings表示关闭编译器不必要的告警信息.
注解是一种预先定义的规则 + 一些与之管理的注解处理器,可以在代码中按定义的规则使用注解,
然后相关的注解处理器就会在适当的时机(编译时,或运行时)做出处理,已完成一些操作,或实现
一些功能,尤其是一些重复的工作.
比如,一共重复工作是根据一个类中的字段生成一个用于创建数据库表的sql.那么就可以定义一个
注解应用在类中,然后定义注解处理器,传递这个类文件个注解处理器方法后,注解处理器根据类中
的注解自动生成sql,不需要手工的根据类文件字段了手动创建sql.
比如@Override这个符号就是一个注解定义,它要求必须要用在方法之前,该注解对应的处理器可以在
编译时检查方法是否覆盖了基类的一个方法,如果没有则编译报错.
2. 定义注解
定义注解主要是定义注解的属性,这些属性称为元注解,主要包括:
(1) @Target 注解作用目标是什么,比如@Override注解的作用目标是类的方法.
所有可用的注解作用目标有:
ElementType.CONSTRUCTOR 构造器
ElementType.FIELD 字段(包含enum类型的字段)
ElementType.LOCAL_VARIABLE 局部变量
ElementType.METHOD 方法
ElementType.PACKAGE 包
ElementType.PARAMETER 参数
ElementType.TYPE 类,接口(包括注解类型本身)或enum声明
(2) @Retention 表示要在什么级别保存该注解信息,所有的参数包括:
RetentionPolicy.SOURCE 注解保存在源码中,会被编译器丢弃
RetentionPolicy.CLASS 注解会保存在class中,但会被VM丢弃
RetentionPolicy.RUNTIME VM在运行器也保留注解,因此可以通过反射机制读取注解
(3) @Documented 表示将此注解包含在Javadoc中
(4) @Inherited 表示允许子类集成父类中用到的注解
注解元素,相当于注解的属性,可用的有:
(1) 8种基本类型(boolean,char,byte,int,short,long,double,float)
(2) String (3)Class (4) enum (5) Annotation
(6) 以上类型的数组
注解元素要么在定义是给个默认值,要么在使用时明确赋值.不能有不确定的值.
定义注解类似于接口定义,使用@interface符号,
注解元素定义也和接口方法定义差不多.
定义注解的例子:
package annotations; import java.lang.annotation.*; @Target(ElementType.METHOD) //表示注解的作用对象是方法 @Retention(RetentionPolicy.RUNTIME) //表示注解信息会在运行时保留 public @interface UseCase // 符号@interface用于定义注解 { public int id(); //整型注解元素 public String description() default "no description"; //String型注解元素,带默认值 }
3. 定义注解处理器
注解处理器中,通常使用反射获取注解信息,比如Class有 Annotation[] getAnnotations()方法,
获取该Class上存在的所有注解,Method也有类似方法.
需要注意的时,定义的注解 相当于集成了Annotation类,因此注解也是一种类型,注解实例可以同调用
注解元素定义中的方法来获取注解元素值,比如UseCase.id()获取注解id元素的值.
注解处理器不会自动触发,也是需要在代码中执行的.
一般注解处理器是基于反射的,所以处理器中处理注解的方法需要传入一个Class类型的参数,
这个Class就是在类定义代码中使用的注解的类.
如下面UseCase的注解处理器trackUseCases中处理方法
trackUseCases(useCases, PasswordUtils.class);就传递了一个参数PasswordUtils.class.
而PasswordUtils类的源码中就使用了注解UseCase.
PasswordUtils 类代码如下:
package annotations; import java.util.*; public class PasswordUtils { @UseCase(id = 47, description = "Passwords must contain at least one numeric") public boolean validatePassword(String password) { return (password.matches("\\w*\\d\\w*")); } @UseCase(id = 48) public String encryptPassword(String password) { return new StringBuilder(password).reverse().toString(); } @UseCase(id = 49, description = "New passwords can't equal previously used ones") public boolean checkForNewPassword(List<String> prevPasswords, String password) { return !prevPasswords.contains(password); } }
注解处理器代码如下:
package annotations; import java.lang.reflect.*; import java.util.*; /** * * 注解UseCase的处理器 * */ public class UseCaseTracker { public static void trackUseCases(List<Integer> useCases,Class<?> cl) { for(Method m:cl.getDeclaredMethods()) { UseCase uc = m.getAnnotation(UseCase.class); //这里注解看成是一种类型 if(uc != null) { System.out.println("Found Use Case:" + uc.id() + " " + uc.description()); //这里作为方法调用,获取了注解元素的值. } } for(int i: useCases) { System.out.println("warning: Missing use case-" + i); } } //List<Integer> useCases 这个参数表示注解处理器可能需要一些额外参数. //这里没有什么实际意义 public static void main(String[] args) { List<Integer> useCases = new ArrayList<Integer>(); Collections.addAll(useCases, 47,48,49,50); trackUseCases(useCases, PasswordUtils.class); } }
赞 赏
微信赞赏 支付宝赞赏
本文固定链接: https://www.jack-yin.com/coding/thinking-in-java/2099.html | 边城网事