Java 注解Annotation研究

目前主流框架都支持注解。比如Android平台上的 Retrofit,EventBus,Butterknife等
Java Web: Spring MVC ,MyBatis等.注解是从Java SDK 1.5 开始启动使用的,使用注解到底有什么好处呢?

对于配置文件需要添加较多逻辑代码来处理,而注解只需要注解元 数据就可以区分,代码整洁,阅读性好,减少配置文件等。

annotation.png

如上图所示:
Java的注解分为元注解和标准注解。

  • 标准注解:系统提供的注解

@Deprecated :表示已经过期,不推荐使用.比如你有一个方法现在不想用了,但是其他人调用了,删掉会影响其他代码。这样用这个标记来说明.

@Documented
@Retention(RetentionPolicy.RUNTIME)//运行期runtime
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})//范围
public @interface Deprecated {
}
@Deprecated
public void test(){
}

@Override 主要作用是覆盖父类方法

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)//在源文件中出现,在编译后会被编译器丢弃
public @interface Override {
}

比如android onCreate方法,覆盖父类方法

 @Override
 protected void onCreate(Bundle savedInstanceState) {
}

比如java toString()方法,覆盖java lang toString方法

 @Override
  public String toString() {
        return super.toString();
   }

@SupressWarning 关闭不当的编译器警告信息
比如

  • 元注解:可以自己定义注解

@Retention 表示需要在什么级别保存该注解信息,标记有下面3个参数可选

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,//注解将被编译器丢弃

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,//注解在class文件可用,但是会VM丢弃

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME//VM运行期也会保留注解,可用用反射机制可用读取对应的数据
}

@Target 表示被描述的注解用于什么地方,可用运用到地方如下

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();//这边是一个ElementType数组
}

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,//用于描述类,接口 或枚举声明

    /** Field declaration (includes enum constants) */
    FIELD,//用于描述域

    /** Method declaration */
    METHOD,//用于描述方法

    /** Formal parameter declaration */
    PARAMETER,//用于描述参数

    /** Constructor declaration */
    CONSTRUCTOR,//用于描述构造器

    /** Local variable declaration */
    LOCAL_VARIABLE,//用于描述局部变量

    /** Annotation type declaration */
    ANNOTATION_TYPE,//用于描述Annotation type

    /** Package declaration */
    PACKAGE,//描述包

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员.

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的,则这个annotation将被用于该class的子类。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

自定义自己的Annotation 格式如下
public @interface 注解名 {定义体}

定义体里面一般如下图所示:

anntion2.png

举个栗子写个Demo吧:
定义一个Person Annotation 里面定义了2个方法 say 和move 方法.

@Target({ElementType.METHOD,ElementType.TYPE,ElementType.LOCAL_VARIABLE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PersonAnnotation {
   public String say() default "hello";
   public String move() default "walk";
  Sex  sex() default Sex.MAN;//枚举类型
}

定义一个UserAnnotation 定义name, age 和 PersonAnnotation annotation

@Target({ElementType.METHOD , ElementType.TYPE,ElementType.FIELD,ElementType.LOCAL_VARIABLE})//可以修饰方法,实例变量,local 变量
@Retention(RetentionPolicy.RUNTIME)
public @interface UserAnnotation {
    String name() default "";
    String age() default "";
    PersonAnnotation person();//使用了Annotation类型
}

定义性别enum.

public enum Sex {
    MAN,WOMEN,OTHER
}

上面的代码定义的不错,那怎么使用呢?答案是反射,直接上代码吧😆
定义User类

@UserAnnotation//因为在Target定义了ElementType.TYPE可以修饰类
public class User {
    @UserAnnotation(name = "Star")//因为在Target中定义了ElementType.FIELD就可以定义在实例变量中拉
    protected String name;
    @UserAnnotation(age = 100)
    int age;
    @UserAnnotation(name = "wong" , age = 1000)
    protected String value;
    @UserAnnotation(name = "GEAK",age = 90)//因为在Target中定义了ElementType.METHOD
    public void getUserInfo(String name,int age){
        System.out.println("the name is:"+name+"\tthe age is:"+age);
    }
    public void getInfo(){
        System.out.println("=======getInfo start=====");
        System.out.println("the name is:"+this.name+"\tthe age is:"+this.age);
        System.out.println("=======getInfo end=====");
    }


}

定义了自己的元数据,下面是测试怎么使用

    @Test
    public void test() {
        //User user = new User();
        System.out.println("startTest");
        Class<User> u = User.class;
        try {
            Method method = u.getMethod("getUserInfo", new Class[]{String.class, int.class});
            UserAnnotation userAnnotation = method.getAnnotation(UserAnnotation.class);
            System.out.println("the name is:" + userAnnotation.name() + "the age is:" + userAnnotation.age());
            if (method != null) {
                method.invoke(u.newInstance(), userAnnotation.name(), userAnnotation.age());
            }
            Field fields[] = u.getDeclaredFields();
            Field f = u.getDeclaredField("value");
            UserAnnotation userAnnotation1 = f.getAnnotation(UserAnnotation.class);
            System.out.println("the f name is:" + userAnnotation1.name() + "the f age is:" + userAnnotation1.age());
            for (Field field : fields) {
                if (field.isAnnotationPresent(UserAnnotation.class)) {
                    System.out.println("the name is:" + field.getName());
                    UserAnnotation annotation = field.getAnnotation(UserAnnotation.class);
                    if (annotation != null) {
                        System.out.println("the name is:" + annotation.name() + "the age is:" + annotation.age());
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

获取对应的User Class ,有下面两种方式

  • 获取Class相关
    1.Class<User> u = User.class; //通过Class直接获取
    2.Class<User> u = Class.forName("User");//通过name获取

  • Class中主要用到的方法
    Method[] getMethods() //获取所有的方法包括父类的方法
    Field[] getFields() //获取所有实例变量包括父类的实例
    Field[] getDeclaredFields()//获取所有的方法不包括父类的方法
    Method[] getDeclaredMethods()//获取所有实例变量不包括父类的实例

  • 获取Annotation
    Method.getAnnotation(Annatation.class)//获取方法上面的Annotation
    Field.getAnnotation(Annatation.class)//获取filed上的Annotation

获取结果:

the name is:GEAKthe age is:90 //获取到方法上的Annotation
the name is:GEAK    the age is:90//获取到方法上的Annotation
the f name is:wongthe f age is:1000//利用反射的机制来调用方法
the name is:name
the name is:Starthe age is:10//获取对应实例的name上的Annotation
the name is:age
the name is:the age is:100
the name is:value
the name is:wongthe age is:1000

总结:
通过Annotation和反射机制来进行合理的配置你的源代码.这样就可以省去大部分的if else或者初始化等工作.

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

推荐阅读更多精彩内容