Java注解总结(一)

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亦是如此。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352