美文网首页编程Android知识Android开发
3分钟快速掌握注解(Annotation)

3分钟快速掌握注解(Annotation)

作者: WaitingAnd | 来源:发表于2016-12-14 12:45 被阅读185次

    由于本人能力有限,文中若有错误之处,欢迎指正。
    转载请注明出处:http://www.jianshu.com/p/e3949dedbe48

    写在前面

    本篇主要讲解注解的基本概念、基本使用,以及容易产生迷惑的地方。实例应用将在后续的简文中继续分析。

    什么是注解?

    官方解释:能够添加到 Java 源代码的语法元数据。类、方法、变量、参数、包都可以被注解,可用来将信息元数据与程序元素进行关联。
    注解(也被成为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。

    通俗来说:其实注解也是一种注释,只不过,注解可以指定保留的时间,以及携带一些相关的数据。而注释只能在源码中存在。

    元注解

    注解当中也会存在注解,这种给自定义注解使用的注解称为---元注解

    • @Rentention
      用来标记自定义注解的有效范围。有三种:
    有效范围
    RetentionPolicy.SOURCE 只在源代码中保留,编译器会忽略,一般都是用来增加代码的理解性或者帮助代码检查之类的,比如@Override
    RetentionPolicy.CLASS 默认选择,能把注解保留到编译后的字节码class文件中,仅仅到字节码文件中,运行时是无法得到的。一般用在动态生成模板代码的类库中。比如ButterKnife
    RetentionPolicy.RUNTIME 注解不仅 能保留到class字节码文件中,还能在运行通过反射获取到,这是最常用的一种。
    • @Target
      规定注解所修饰的对象范围。
    修饰范围
    ElementType.CONSTRUCTOR 构造器声明
    ElementType.FIELD 成员变量、对象、属性(包括enum实例)
    ElementType.LOCAL_VARIABLE 局部变量声明
    ElementType.METHOD 方法声明
    ElementType.PACKAGE 包声明
    ElementType.PARAMETER 参数声明
    ElementType.TYPE 类、接口(包括注解类型)或enum声明
    • @Documented
      标记着此注解会被javadoc工具提取成文档。

    • @Interited
      允许子类继承父类中的注解。将在最后以示例的形式讲解

    自定义注解

    我们可以在使用元注解的基础上,使用 @interface关键字实现自定义注解。其默认继承自:java.lang.annotation.Annotation。如下所示:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @Documented
    @Inherited
    public @interface MyAnnotation {
        int value() default 1;
        boolean canBeNull() default false;
    }
    

    上面的自定义注解可以这样使用:
    @MyAnnotation @MyAnnotation() @MyAnnotation(1) @MyAnnotation(value=1) @MyAnnotation(canBuNull = true) @MyAnnotation(value = 1,canBuNull = true)

    不能这样使用
    @MyAnnotation(true)
    因为当括号中的内容不以键值对的形式出现时,默认使用的是value =

    注解元素

    注解元素名来自于注解类的方法名,且有以下特点:

    1. 方法返回值只能是基本数据类型String, Class, annotation, enum它们的一维数组
    2. 所有方法没有方法体没有参数没有修饰符,默认为 public abstract修饰。不允许抛异常
    3. 若只有一个默认元素,可直接用value()函数。一个元素都没有表示该注解为标记注解(Mark Annotation)

    默认值

    注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定。
    注解元素的值不能为null

    @Retention(RetentionPolicy.RUNTIME)
    @Target({FIELD, TYPE, METHOD})
    public @interface MyAnnotation {
    
        int value() default 1;
    
        boolean[] canWrite() default {true, false};
    
        Class test();  // 定义的时候没有默认值,在使用的时候必须指定
    }
    
    // 使用示例
    @MyAnnotation(value = 23, test = Integer.class)
    int age;
    

    @Interited元注解

    允许子类继承父类中的注解。
    当被@Inherited标注的注解的RetentionRetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用反射去查询一个@Inherited注解类型的注解时,反射代码检查将展开工作:检查class和其父类,直到指定的注解类型被发现,或者到达类继承结构的顶层Object

    相对于其它元注解,@Interited元注解比较特殊,下面将以示例的形式帮助大家更好的理解它的作用:

    首先我们定义一个自定义注解@MyAnnotation并使用@Interited标记

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
    @Inherited
    public @interface MyAnnotation {
    
        String value() default "";
    }
    

    定义一个类SuperClass

    @MyAnnotation("SuperClass")
    public class SuperClass {
    
        @MyAnnotation("SuperClass::testMethod")
        public void testMethod(){
        }
    }
    

    定义一个类SubClass继承自SuperClass

    public class SubClass extends SuperClass {
    
    }
    

    测试主程序:

    public class Main {
    
        public static void main(String[] args) throws Exception{
    
            testSuper();
    
            testSub();
        }
    
        private static void testSub() {
            MyAnnotation myAnnotation = SubClass.class.getAnnotation(MyAnnotation.class);
            if(myAnnotation == null){
                System.out.println("注解不存在");
                return;
            }
            String value = myAnnotation.value();
            System.out.println(value);
        }
    
        private static void testSuper() {
            MyAnnotation myAnnotation = SuperClass.class.getAnnotation(MyAnnotation.class);
            if(myAnnotation == null){
                System.out.println("注解不存在");
                return;
            }
            String value = myAnnotation.value();
            System.out.println(value);
        }
    
    }
    

    运行以上程序,testSub() testSuper() 都打印的是在SuperClass类标记的注解值SuperClass。而SubClass类中没有使用注解,所以,可以确定是从父类中继承过来的。这里面起到关键作用的就是@Interited元注解

    还有很多种情况,大家可以自行编码尝试,下面给出总结
    注: 父类使用的注解被@Inherited标注的情况下

    1. 如果父类的注解是作用在类上面,那么子类是可以继承过来。
    2. 如果父类的注解作用在方法上面,那么子类也可以继承过来。
    3. 如果子类重写了父类中使用了注解的方法,那么子类将无法继承该方法的注解。
    4. 实现类不能继承接口中的注解。

    相关文章

      网友评论

      本文标题:3分钟快速掌握注解(Annotation)

      本文链接:https://www.haomeiwen.com/subject/wnlimttx.html