自定义注解
自定义注解可以用来在编译时期插入代码或者做一些特殊的操作,以下是自定义注解的几种用法:
- 生成文档等类似的说明:
这是自定义注解最常见也是最基本的应用场景,在Java中有原生的注解(如@Override, @Deprecated等)也是为了辅助生成文档而存在。
例如下面的注解用于描述类或方法的作用:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Description {
String value() default "";
}
使用示例:
@Description("This is a class for demo")
public class DemoClass {
@Description("This is a method for demo")
void demoMethod(){
....
}
}
- 模块化处理:
对于不同模块、功能,需要处理的参数不一样,通过注解方式方便灵活处理。比如针对数据库实体类做了一个注解表示该类对应的表名,可以在ORM工具从实体到表建立映射关系时根据这个注解完成处理。
@Target(ElementType.TYPE)
public @interface Table {
String name();
}
使用示例:
@Table(name = "t_user")
public class UserEntity{
Long userId;
String userName;
}
- 用于权限检查:
对于某些内部API调用,在运行时进行权限检查可能来不及,所以可以采用注解的方式在编译期检查程序的合法性,从而避免在运行时发现错误。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
String[] value();//permissions needed by the method
}
使用示例:
@Permission({"android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE"})
public void saveFile() {
//写文件代码
}
-
用于AOP拦截:
通过自定义注解,配合AOP技术可以实现日志记录、异常处理、性能统计等通用逻辑。 -
更多场景参考第4点,如Ioc容器等。
单参数注解实现示例:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SortableField {
int order() default 0;
}
当一个对象包含多个SortableField字段时,可以通过order属性的值来指定排序的优先级,即order值小的字段先进行排序处理。使用示例:
public class User{
@SortableField(order = 2)
private String name;
@SortableField(order = 1)
private int age;
}
在对User列表进行排序时,可以按照@SortableField中order的值从小到大排列:
List<User> userList=new ArrayList<>();
userList.add(user1);
userList.add(user2);
Collections.sort(userList, new Comparator<User>() {
public int compare(User o1, User o2) {
Field[] fs = User.class.getDeclaredFields();
for (Field f : fs) {
if (f.isAnnotationPresent(SortableField.class)) {
Order order = f.getAnnotation(SortableField.class).order();
try {
f.setAccessible(true);
Object v1 = f.get(o1);
Object v2 = f.get(o2);
if (compareObject(v1, v2) != 0) {
return order == Order.ASC ? compareObject(v1, v2) : -compareObject(v1, v2);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
throw new RuntimeException("no sortable field found");
}
});
该实现中首先获取到User中所有字段,再通过isAnnotationPresent判断是否包含需要排序的字段。然后通过getAnnotation获取该字段上@SortableField注解的值,并且读取该字段的值对两个对象进行比较。
元注解(meta-annotation)是指用来注解其它注解的注解,Java 5.0定义了4个标准的meta-annontation类型,分别是@Retention、@Target、@Inherited和@Documented。
以下是Java 5.0定义的4个meta-annotation:
- @Retention:
注解的保留期,在什么范围内有效。共有三个值:
- RetentionPolicy.SOURCE:Annotation只保留在源代码中。
- RetentionPolicy.CLASS:Annotation保留到class文件中,但是运行时不可见。(默认值)
- RetentionPolicy.RUNTIME: Annotation保留到class文件中,同时运行时可通过反射机制获取到,是最常用的一种方式。
- @Target:
说明注解所修饰的范围。共有以下几个取值:
- ElementType.ANNOTATION_TYPE: 可以给一个注解进行注解。
- ElementType.CONSTRUCTOR: 可以给构造方法进行注解。
- ElementType.FIELD: 可以给属性进行注解。
- ElementType.LOCAL_VARIABLE: 可以给局部变量进行注解。
- ElementType.METHOD: 可以给方法进行注解。
- ElementType.PACKAGE: 可以给一个包进行注解。
- ElementType.PARAMETER: 可以给一个方法内的参数进行注解。
- ElementType.TYPE: 可以给一个类型进行注解,比如类、接口、枚举。
-
@Inherited:
被@Inherited修饰的注解能被继承。如果一个使用了@Inherited修饰的Annotation类型被用于一个class,则这个Annotation将被用于该class的子类。 -
@Documented:
一个被@Documented注解的注解类会在javadoc生成文档时显示所有注解的信息。****