Java注解简介


Java注解(Annotation)是JDK1.5引入的注释机制。Java语言中的类、方法、变量、参数和包等都可以被标注。Java注解是一种引用数据类型,编译之后也是生成.class文件。

元注解

用来标“注解类型”的注解称为元注解。JDK1.5定义了4个标准的元注解类型,用来提供对其他注解类型作说明。

  1. @Target注解:该注解说明被标注的注解的使用范围;

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        ElementType[] value();
    }
    

    @Target注解源码如上,可以看到Target注解包含一个ElementType[]属性,ElementType是一个枚举类,其值及作用如下:

    public enum ElementType {
        // 可以标注类、接口(包括注解)、枚举声明
        TYPE,
        // 可标注属性(包括枚举常量)声明
        FIELD,
        // 可标注方法声明
        METHOD,
        // 可标注形参声明
        PARAMETER,
        // 可标注构造函数声明
        CONSTRUCTOR,
        // 可标注局部变量声明
        LOCAL_VARIABLE,
        // 可标注注解声明
        ANNOTATION_TYPE,
        // 可标记包声明
        PACKAGE,
        TYPE_PARAMETER,
        TYPE_USE
    }
    

    可以看到Target注解本身被@Target(ElementType.ANNOTATION_TYPE)注解修饰,说明Target注解只能出现注解声明语句前。

    当一个注解中有属性,那么必须给属性赋值,除非该属性有default指定的默认值。

  2. @Retetion:该注解用来标注被标注注解的生命周期,其源代码如下:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
        RetentionPolicy value();
    }
    
    public enum RetentionPolicy {
        // 注解被保留在java源文件中,编译器会忽略这些注解(有点类似注释)
        SOURCE,
        // 编译器会将这些注解保留在字节码文件(.class文件)中,但虚拟机运行时不需要读取
        // 默认行为,当定义注解时没显示声明Retention时默认使用@Retention(RetentionPolicy.CLASS)
        CLASS,
        // 编译器会将这些注解保存在字节码文件中,虚拟机在运行时可以通过反射读取。
        RUNTIME
    }
    
  3. @Documented:标记注解是否包含在用户文档中;

  4. @Inherited :被该注解标注的注解具有继承性,Demo如下;

    // 自定义两个注解MyAnno1和MyAnno2,其中MyAnno1标注为@Inherited。
    // Base类使用MyAnno1和MyAnno2标注,Sub类继承Base
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface MyAnno1 {}
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnno2 {}
    
    @MyAnno1
    @MyAnno2
    public class Base {
        public Base() {
            // 通过反射获取Base类的注解
            Annotation[] annotations = Base.class.getAnnotations();
            System.out.println("Base:" + Arrays.toString(annotations));
       }
    }
    
    public class Sub extends Base {
        public Sub() {
            Annotation[] annotations = Sub.class.getAnnotations();
            Syst
    em.out.println("Sub:" + Arrays.toString(annotations));
        }
    }
    // 测试代码
    public class AnnotationDemo {
        public static void main(String[] args) {
            Base base = new Base();
            Sub sub = new Sub();
        }
    }
    

    运行结果如下:

Inherited注解测试运行结果

可以看到Sub只继承了注解MyAnno1,并未继承注解MyAnno2(另Base打印了两行,应当是Sub构造函数隐式调用了父类的无参构造函数引起的)。

  1. @Repeatable:JDK1.8新加入,标识某个注解可以在同一个声明上多次使用。

自定义注解

[访问修饰符] @interface 注解类名{
    // 接口方法,默认为public abstract
    int value() default 1;
}

注解使用

如果无法读取注解信息,那注解不会比注释更有用。通过Java反射机制,我们可以读取注解信息,示例如下:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Profile {
    int id();
    String name();
}

public class AnnotationDemo {
    @Profile(id = 1, name = "Tom")
    private String field;

    public static void main(String[] args) {
        Field field = null;
        try {
            field = AnnotationDemo.class.getDeclaredField("field");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        assert field != null;
        Profile profile = field.getAnnotation(Profile.class);
        System.out.println("id:" + profile.id() + ",name:" + profile.name());
    }
}

运行结果如下:

获取注解信息测试结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值