自定义注解

自定义注解可以用来在编译时期插入代码或者做一些特殊的操作,以下是自定义注解的几种用法:

  1. 生成文档等类似的说明:
    这是自定义注解最常见也是最基本的应用场景,在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(){
        ....
    }
}
  1. 模块化处理:
    对于不同模块、功能,需要处理的参数不一样,通过注解方式方便灵活处理。比如针对数据库实体类做了一个注解表示该类对应的表名,可以在ORM工具从实体到表建立映射关系时根据这个注解完成处理。
@Target(ElementType.TYPE)
public @interface Table {
    String name();
}

使用示例:

@Table(name = "t_user")
public class UserEntity{
    Long userId;
    String userName;
}
  1. 用于权限检查:
    对于某些内部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() {    
    //写文件代码
}
  1. 用于AOP拦截:
    通过自定义注解,配合AOP技术可以实现日志记录、异常处理、性能统计等通用逻辑。

  2. 更多场景参考第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:

  1. @Retention:
    注解的保留期,在什么范围内有效。共有三个值:
  • RetentionPolicy.SOURCE:Annotation只保留在源代码中。
  • RetentionPolicy.CLASS:Annotation保留到class文件中,但是运行时不可见。(默认值)
  • RetentionPolicy.RUNTIME: Annotation保留到class文件中,同时运行时可通过反射机制获取到,是最常用的一种方式。
  1. @Target:
    说明注解所修饰的范围。共有以下几个取值:
  • ElementType.ANNOTATION_TYPE: 可以给一个注解进行注解。
  • ElementType.CONSTRUCTOR: 可以给构造方法进行注解。
  • ElementType.FIELD: 可以给属性进行注解。
  • ElementType.LOCAL_VARIABLE: 可以给局部变量进行注解。
  • ElementType.METHOD: 可以给方法进行注解。
  • ElementType.PACKAGE: 可以给一个包进行注解。
  • ElementType.PARAMETER: 可以给一个方法内的参数进行注解。
  • ElementType.TYPE: 可以给一个类型进行注解,比如类、接口、枚举。
  1. @Inherited:
    被@Inherited修饰的注解能被继承。如果一个使用了@Inherited修饰的Annotation类型被用于一个class,则这个Annotation将被用于该class的子类。

  2. @Documented:
    一个被@Documented注解的注解类会在javadoc生成文档时显示所有注解的信息。****

posted @ 2023-03-21 00:18  懒懒初阳  阅读(143)  评论(0编辑  收藏  举报