美文网首页我爱编程
Java注解总结(一)

Java注解总结(一)

作者: TheTwo | 来源:发表于2018-04-16 18:38 被阅读0次

    Java注解总结(一)


    什么是注解

    Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据。

    说白了注解就是定义在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。这里的注释是给机器看的而不是给人看的。

    那么如何定义一个注解

    定义注解类不能使用class、enum,也不能使用interface,而是使用@interface。
    

    public @interface MyAnnotation{}

    1. 使用注解

    注解可以作用在:类(接口或枚举)、属性、方法、构造器、包、参数、局部变量
    具体代码如下

    @MyAnnotation
    public class Person {
        private static final String TAG = Person.class.getSimpleName();
        @MyAnnotation
        private String name;
        @MyAnnotation
        private int age;
    
        @MyAnnotation
        public Person() {
        }
    
        @MyAnnotation
        public Person(@MyAnnotation     String name, @MyAnnotation int age)     
        {
            this.name = name;
            this.age = age;
        }
    
        @MyAnnotation
        public String getName()
        {
            return name;
        }
    
        public int getAge() 
        {
            return age;
        }
    
        public void setName(String name)     
        {
            this.name = name;
        }
    
        public void setAge(int age) 
        {
            this.age = age;
        }
    
        public void test() 
        {
            @MyAnnotation
            String test = "我是测试数据";
            Log.d(TAG, test);
        }
    }
    

    2. 注解中的属性(其实这里叫属性更加简单明了一点 --- 设置属性的值获取属性的值)

    • 定义注解时也可以定义属性
      具体代码如下,还是刚才的例子。
    
    public @interface MyAnnotation {
    
        String name() default "张三";
    
        int age() default 18;
    
        String[] clothes();
    }
    

    定义一个注解的属性时候可以有默认值,可以没有默认值。如果有指定默认值,在使用注解时,可以不指定属性的值。没有的话就必须给注解属性赋值。
    定义属性类型可以是

    1. 所有基本类型(int,float,boolean,byte,double,char,long,short)
    2. String
    3. Class
    4. enum
    5. Annotation
    6. 上述类型的数组
    • 定义注解时也可以定义属性
    @MyAnnotation(name = "张三", age = 18, clothesColor = {"红色", "蓝色"})
    public class Person {
    ......
    }
    
    在定义注解和使用时应当注意
    1. 注的属性后面要有一对圆括号,而且圆括号内不能给出东西。就像是无参的方法一样;
    2. 数组的属性默认值:string[] clothesColor() default {"红色","蓝色","绿色"},这里不能使用new string[]{"红色","蓝色","绿色"},使用注解时,在给数组属性赋值时的格式:@MyAnnotation(clothesColor = {"红色", "蓝色"});

    元注解

        上述定义的注解时可以在类(接口或枚举)、属性、方法、构造器、包、参数、局部变量上使用的,那么如何限定自定义注解的作用目标呢和和使用范围?那么就应使用元注解。相信元注解的作用都很清楚了,就是用来修饰自定义注解的,简称-注解的注解。
    

    1. 元注解都有哪些?

    1. @Retention : 指定注解信息在哪个阶段存在Source Class RuntimeRetentionPolicy.SOURCE:这种类型的Annotations只在源代码级别保留,编译时就会被忽略
      RetentionPolicy.CLASS:这种类型的Annotations编译时被保 留,在class文件中存在,但JVM将会忽略
      RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,所以 他们能在 运行时被JVM或其他使用反射机制的代码所读取和使用.

    2. @Target : 指定注解修饰目标对象类型TYPE 类、接口FIELD 成员变量METHOD 方法

    3. @Documented :使用该元注解修饰,该注解的信息可以生成到javadoc 文档中

    4. @Inherited :如果一个注解使用该元注解修改,应用注解目标类的子类都会自动继承该注解

                                                                                          --以上四种类型元注摘自网络
      

    Target注解

        在定义注解时可以限制注解的作用目标!例如让注解只能作用在类和方法上。这需要使用元注解:@Target。该注解有一个属性value,类型为ElementType[],它是枚举类型。具体源码如下:
    
    public enum ElementType {
        //类、接口(包括注解类型)或enum声明
        TYPE,
    
        //字段(域)声明,包括enum实例
        FIELD,
    
        //方法声明 
        METHOD,
    
        //于参数声明 
        PARAMETER,
    
        //构造函数声明
        CONSTRUCTOR,
    
        //局部变量声明
        LOCAL_VARIABLE,
    
        //注解声明(应用于另一个注解上)
        ANNOTATION_TYPE,
    
        //包声明 
        PACKAGE,
    
        //类型参数声明(1.8新加入)
        TYPE_PARAMETER,
        
        //类型使用声明(1.8新加入)
        TYPE_USE
    }
    

    例如将MyAnnotation注解作用在方法和字段上

    @Target(value = {FIELD,METHOD})
    public @interface MyAnnotation {
     .....
    }
    

    那么现在如果要把MyAnnotation定义在类上呢,那是不存在的。编译器会报错,只能在你指定的作用目标上。

    public class Person {
        @MyAnnotation(name = "张三")
        private String name;
        @MyAnnotation(name = "张三")
        public String getName() {
            return name;
        }
        ......
    }
    

    @Inherited

    此注解的作用不是注解继承,而是当一个自定义注解应用了此注解,那么子类对象就可以通过getAnnotations()获取父类被修饰的注解。

    @Inherited
    @Target(value = {FIELD,METHOD,TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
        String name() ;
        int age() default 18;
        String[] clothesColor() default {"红色","蓝色"};
    }
    
    @MyAnnotation(name = "李四",age = 20,clothesColor = {"紫色"})
    public class Person {
    ......
    }
    
    public class ManPerson extends Person {
    
    }
    
    //测试
    Person person = new ManPerson();
                Log.e(TAG + "--Inherited注解:", Arrays.toString(person.getClass().getAnnotations()));
    //结果
    MainActivity--@Inherited注解: [@com.example.annotationdemo.annotation.MyAnnotation(age=20, clothesColor=[紫色], name=李四)]
    

    通过反射来读取注解

    Java在java.lang.reflect 反射包下新增了AnnotatedElement接口,它主要用于表示目前正在 JVM 中运行的程序中已使用注解的元素,通过该接口提供的方法可以利用反射技术地读取注解的信息
    返回值 方法名称 说明
    Annotation getAnnotation(Class<A> annotationClass) 该元素如果存在指定类型的注解,则返回这些注解,否则返回 null。
    Annotation[] getAnnotations() 返回此元素上存在的所有注解,包括从父类继承的
    boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。
    Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。。

    AnnotatedElement中相关的API方法

    返回值 方法名称 说明
    Annotation getAnnotation(Class<A> annotationClass) 该元素如果存在指定类型的注解,则返回这些注解,否则返回 null。
    Annotation[] getAnnotations() 返回此元素上存在的所有注解,包括从父类继承的
    boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。
    Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。。

    使用

    @Inherited
    @Target(value = {FIELD}) //只能作用在类中字段上
    @Retention(RetentionPolicy.RUNTIME)//运行时被JVM或其他使用反射机制的代码所读取和使用.
    public @interface MyAnnotation {
        String name() default "";
    }
    
    public class Person {
        @MyAnnotation(name = "张三")
        public String name;
    }
    
    //测试
    Class<Person> personClass = Person.class;
                //获取该类中所有字段
                try {
                    Field namef = personClass.getDeclaredField("name");
                    boolean annotationPresentName = namef.isAnnotationPresent(MyAnnotation.class);
                    //如果存在此注解
                    if (annotationPresentName) {
                        //获取此注解
                        MyAnnotation annotation = namef.getAnnotation(MyAnnotation.class);
                        //打印注解的值
                        Log.e(TAG + "姓名", annotation.name());
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                }
    //结果
    MainActivity姓名: 张三
    
    同理如果注解在类上可以用Class<T>.getAnnotation(ClassannotationClass)获取指定类型的注解。

    Constructor,Method亦是如此。

    相关文章

      网友评论

        本文标题:Java注解总结(一)

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