java - 注解

1. 元注解

元注解:用在注解上的注解,java1.5后添加的4个元注解:

  • @Target
  • @Retention
  • @Documented
  • @Inherited

在java1.8又添加了两个注解:

  • @Native
  • @Repeatable

先说明下这几个注解.

@Target 修饰的对象范围

取值(ElementType)有:

  • 1.CONSTRUCTOR:用于描述构造器
  • 2.FIELD:用于描述域
  • 3.LOCAL_VARIABLE:用于描述局部变量
  • 4.METHOD:用于描述方法
  • 5.PACKAGE:用于描述包
  • 6.PARAMETER:用于描述参数
  • 7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

当注解类型声明中没有@Target元注解,则默认为可适用所有的程序元素。

@Retention 注解保留到哪个时期(生命周期)

取值(RetentionPoicy)有:

  • 1.SOURCE:在源文件中有效(即源文件保留)
  • 2.CLASS:在class文件中有效(即class保留)
  • 3.RUNTIME:在运行时有效(即运行时保留)

默认CLASS,可以看下源码中提解释:

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,

    /**
     * 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
}

@Documented 标志可文档化

被标注的程序成员的公共API,因此可以被例如javadoc此类的工具被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化

@Inherited 将注解内容传递到子类

若是方法被重写则得不到父类方法中的注解内容,关于该方法所有的内容都被重新定义了.

在类上的注解会被传递该子类,方法也可以但重写了则不会在传递给子类
再次捋清楚下:

  • 如果父类的注解是定义在类上面,那么子类是可以继承过来的
  • 如果父类的注解定义在方法上面,那么子类仍然可以继承过来
  • 如果子类重写了父类中定义了注解的方法,那么子类将无法继承该方法的注解
  • 即子类在重写父类中被@Inherited标注的方法时,会将该方法连带它上面的注解一并覆盖掉

2.常见的Java注解

我们平时直接使用java提供几个注解:@Override @Deprecated @SuppressWarnings @FunctionalInterface,下面逐个看下其定义

  • @Override :告知服务器,我们要覆盖父类中的当前方法.

     @Target(ElementType.METHOD)
     @Retention(RetentionPolicy.SOURCE)
     public @interface Override {
     }
    
  • @Deprecated :告知编译器,某一程序元素不建议使用了

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
    public @interface Deprecated {
    }
    
  • @SuppressWarnings 忽略特定的警告
    用于告知编译器忽略特定的警告信息,例在泛型中使用原生数据类型,编译器会发出警告,当使用该注解后,则不会发出警告。

    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
        String[] value();
    }
    

    可以接受多个参数例如:
    @SupressWarning(value={"uncheck","deprecation"})

    接受的类型:

    • all: to suppress all warnings
    • boxing: to suppress warnings relative to boxing/unboxing operations
    • cast: to suppress warnings relative to cast operations
    • dep-ann: to suppress warnings relative to deprecated annotation
    • deprecation: to suppress warnings relative to deprecation
    • fallthrough: to suppress warnings relative to missing breaks in switch statements
    • finally: to suppress warnings relative to finally block that don’t return
    • hiding: to suppress warnings relative to locals that hide variable
    • incomplete-switch: to suppress warnings relative to missing entries in a switch statement (enum case)
    • nls: to suppress warnings relative to non-nls string literals
    • null: to suppress warnings relative to null analysis
    • rawtypes: to suppress warnings relative to un-specific types when using generics on class params
    • restriction: to suppress warnings relative to usage of discouraged or forbidden references
    • serial: to suppress warnings relative to missing serialVersionUID field for a serializable class
    • static-access: to suppress warnings relative to incorrect static access
    • synthetic-access: to suppress warnings relative to unoptimized access from inner classes
    • unchecked: to suppress warnings relative to unchecked operations
    • unqualified-field-access: to suppress warnings relative to field access unqualified
    • unused: to suppress warnings relative to unused code
  • @FunctionalInterface 保证该接口是函数式接口
    用户告知编译器,检查这个接口,保证该接口是函数式接口,即只能包含一个抽象方法,否则就会编译出错。

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

3. 自定义注解

Annotaion不影响程序代码的执行,无论增加、删除Annotation,代码都始终如一地执行。
也就是说:如果我们不去解析注解,它就没什么作用和影响.
在 java.lang.Class 中末尾有4个涉及的解析注解的方法:

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass)

    返回改程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。

  • Annotation[] getAnnotations()

    返回该程序元素上存在的所有注解。

  • boolean isAnnotationPresent(Class<?extends Annotation> annotationClass)

    判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.

  • Annotation[] getDeclaredAnnotations()

    返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

除此之外还有写注意事项:

  • 成员类型受限:原始类型,String,Class,Annotation,Enumeration
  • 注解类只有一个成员时,必须取名为value(),在使用时可以忽略成员名和赋值号(=)
  • 注解类可以没有成员,称之为标识注解

4. 实践自定义注解

首先看下接下来要实现的相关类:


类结构

FruitName 水果名称

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitName {

    String value() default "";

}

FruitColor 水果颜色

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FruitColor {

    public enum Color {
        BLUE("蓝色"), RED("红色"), GREEN("绿色");

        private String name;

        public String getName() {
            return name;
        }

        Color(String name) {
            this.name = name;
        }
    }

    Color value() default Color.GREEN;
}

FruitProvider 供应商信息

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FruitProvider {

    int id() default 1;

    String address() default "";

    String providerName() default "";

}

接下来到使用类了

Apple 使用注解

public class Apple {

    @FruitName("苹果")
    public String name;

    @FruitColor(FruitColor.Color.GREEN)
    public String color;

    @FruitProvider(id=1001,address = "美国硅谷",providerName = "苹果公司")
    public String  provider;

}

FruitAnnotationParser 注解解析类

public class FruitAnnotationParser {

    public static void parse() {
        Field[] fields = Apple.class.getDeclaredFields();

        for (Field field : fields) {
            if (field.isAnnotationPresent(FruitName.class)) {
                FruitName fruitName = field.getAnnotation(FruitName.class);
                String value = fruitName.value();
                System.out.println(value);

            } else if (field.isAnnotationPresent(FruitColor.class)) {
                FruitColor fruitColor = field.getAnnotation(FruitColor.class);
                FruitColor.Color color = fruitColor.value();
                System.out.println(color.getName());

            } else if (field.isAnnotationPresent(FruitProvider.class)) {
                FruitProvider provider = field.getAnnotation(FruitProvider.class);
                String address = provider.address();
                int id = provider.id();
                String providerName = provider.providerName();
                System.out.println(String.format("providerName:%s id:%d address:%s", providerName, id, address));

            }
            
        }
    }
}

测试

public class FruitTest {

    public static void main(String[] args) {
        FruitAnnotationParser.parse();
    }

}

输出:

苹果
绿色
providerName:苹果公司 id:1001 address:美国硅谷

注解理解之后使用起来还是比较简单的,解析注解的套路就那么4个,解析的过程都差不多.

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

推荐阅读更多精彩内容