zoukankan      html  css  js  c++  java
  • 类型注解与重复注解一些限制

    类型注解

    原来注解只能用于声明,从JDK 8开始,注解还可以用于大多数使用类型的地方,这种注解称为类型注解。类型注解允许工具对代码执行额外的检查,从而帮助避免错误。javac本身一般不执行这些检查,这种工具需要作为编译器插件发挥作用。

    例子

    @Target(ElementType.TYPE_USE)
    public @interface TypeAnno {
    }
    
    @Target(ElementType.TYPE_USE)
    public @interface MaxLen {
    
        int value();
    
    }
    
    @Target(ElementType.TYPE_USE)
    public @interface Unique {
    }
    
    @Target(ElementType.TYPE_PARAMETER)
    public @interface What {
    
        String description();
    
    }
    
    @Target(ElementType.FIELD)
    public @interface NotNull {
    }
    
    @Target(ElementType.METHOD)
    public @interface Recommended {
    }
    
    // 注解类型参数
    public class TypeTest<@What(description = "Generic data type") T> {
    
        // 注解字段类型
        private @TypeAnno String first;
    
        // 注解字段声明
        private @NotNull String second;
    
        // 注解数组元素类型
        private @TypeAnno Integer[] nums;
    
        // 注解数组级别
        private String @MaxLen(5) [] @MaxLen(10) [] data;
    
        // 注解构造函数
        public @Unique TypeTest() {
        }
    
        // 注解this的类型
        public int f1(@TypeAnno TypeTest<T> this, int x) {
            return 10;
        }
    
        // 注解方法返回类型
        public @TypeAnno Integer f2(int j, int k) {
            return j + k;
        }
    
        // 注解方法声明
        public @Recommended Integer f3(String str) {
            return str.length() / 2;
        }
    
        // 注解异常类型
        public void f4() throws @TypeAnno NullPointerException {
            // ...
        }
    
        public static void test() {
            TypeTest<@TypeAnno Integer> obj1 = new TypeTest<>(); // 注解实际类型参数
            @TypeAnno TypeTest<Integer> obj2 = new @TypeAnno TypeTest<>(); // 注解实例类型
    
            Object x = new Integer(10);
            Integer y;
    
            y = (@TypeAnno Integer) x; // 注解强制类型转换
        }
    
    }
    
    // 注解被继承的类型
    public class SubTypeTest extends @TypeAnno TypeTest<Integer> {
        // ...
    }
    

    注意

    • 类型注解必须包含ElementType.TYPE_USE作为目标。
    • 类型注解需要放到应用该注解的类型前面。
    • 不能对void返回类型添加注解。
    • @Target可以用于消除声明注解和类型注解的模糊性问题,比如上面例子中@TypeAnno注解字段类型而@NotNull注解字段声明;@TypeAnno注解方法返回类型而@Recommended注解方法声明。

    this对象

    this是所有实例方法的隐式参数,它的类型必须是其类的类型。类型注解可以注解this的类型,但是需要使用JDK 8的一个新特性,从JDK 8开始可以显式地将this声明为方法的第一个参数。

    除非是要注解this的类型,否则没必要声明this。并且显示声明this没有改变方法签名,因为默认也会隐式声明this。


    重复注解

    JDK 8新增了另一种注解特性,这种特性称为重复注解,它允许在相同元素上重复应用同一个注解。

    @Repeatable注解

    可重复的注解必须用@Repeatable进行注解。@Repeatable定义在java.lang.annotation中,它的value域指定了重复注解的容器类型。源码如下所示:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Repeatable {
    
        /**
         * Indicates the <em>containing annotation type</em> for the
         * repeatable annotation type.
         * @return the containing annotation type
         */
        Class<? extends Annotation> value();
        
    }
    

    容器注解

    重复注解的容器类型被指定为注解。容器注解的value域是重复注解类型的数组。要创建重复注解,必须创建容器注解,然后将该容器注解的类型作为@Repeatable注解的参数。

    @Retention(RetentionPolicy.RUNTIME)
    @Repeatable(RepeatedAnnos.class)
    public @interface RepeatableAnno {
    
        String name() default "test";
    
        int value() default 100;
    
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    public @interface RepeatedAnnos {
    
        RepeatableAnno[] value();
    
    }
    

    获取重复注解的方式

    • 使用getAnnotation()方法获取重复注解,要使用容器注解作为参数,而不是重复注解。
    public class RepeatableTest {
    
        @RepeatableAnno(name = "first annotation", value = 10)
        @RepeatableAnno(name = "second annotation", value = 20)
        public static void test() {
            RepeatableTest obj = new RepeatableTest();
    
            try {
                Class<?> c = obj.getClass();
                Method m = c.getMethod("test");
                Annotation anno = m.getAnnotation(RepeatedAnnos.class);
                System.out.println(anno);
            } catch (NoSuchMethodException e) {
                System.out.println("Method Not Found.");
            }
        }
    
        public static void main(String[] args) throws Exception {
            test();
        }
    
    }
    

    上面例子的输出如下:
    @RepeatedAnnos(value=[@RepeatableAnno(name=first annotation, value=10), @RepeatableAnno(name=second annotation, value=20)])

    • 获取重复注解的另一种方式是使用JDK 8添加到AnnotatedElement中的新方法,它们能够直接操作重复注解。这些方法包括getAnnotationsByType()和getDeclaredAnnotationsByType()。
    Annotation[] annos = m.getAnnotationsByType(RepeatableAnno.class);
    for (Annotation anno : annos) {
        System.out.println(anno);
    }
    

    一些限制

    使用注解声明有一些限制:

    • 一个注解不能继承另一个注解。
    • 注解声明的成员方法不能带参数。
    • 注解声明的成员方法不能指定throws子句。
    • 注解不能被泛型化。



    Java8对注解处理提供了两点改进:可重复的注解及可用于类型的注解

    1.可重复注解

    Java8以前定义注解:

    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
        String value() default "mobei";
    }
    

    使用:


     
    image.png

    可以看到这时当做重复注解使用就报错了。
    如果要使用重复注解,必须先定义一个容器:

    //注解容器
    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotations {
        MyAnnotation[] value();
    }
    

    在重复注解上标注@Repeatable注解并指定容器类:

    //使用可重复注解:①必须使用@Repeatable注解标注该注解②在@Repeatable注解中指定该注解的注解容器
    @Repeatable(MyAnnotations.class)
    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})//TYPE_PARAMETER:J8中新增加的类型注解
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
        String value() default "mobei";
    }
    

    使用:


     
    image.png

    不报错,测试:

        @Test
        public void test1() throws Exception {
            Class<TestAnnotation> clazz = TestAnnotation.class;
            Method m1 = clazz.getMethod("show");
            MyAnnotation[] mas = m1.getDeclaredAnnotationsByType(MyAnnotation.class);
            for (MyAnnotation myAnnotation : mas) {
                System.out.println(myAnnotation.value());
            }
        }
    

    输出:

    Hello
    World
    
    2.类型注解

    在上面的MyAnnotation的@Target注解中加入TYPE_PARAMETER

    //使用可重复注解:①必须使用@Repeatable注解标注该注解②在@Repeatable注解中指定该注解的注解容器
    @Repeatable(MyAnnotations.class)
    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})//TYPE_PARAMETER:J8中新增加的类型注解
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
        String value() default "mobei";
    }
    

    可以修饰参数:

    @MyAnnotation("Hello")
    @MyAnnotation("World")
    public void show(@MyAnnotation("abc") String str){
    }
    
  • 相关阅读:
    关于jar项目发布(windows)
    SpringBoot 基础(一) mybatis 通过druid配置多数据库
    redis 基础(二) Redis安装
    测试开发3年,我决定去读个名校硕士
    大厂程序员凡尔赛的一天
    假如我拥有字节工牌。。。
    上海有哪些牛逼的互联网公司?
    那些学计算机的女生后来都怎么样了?
    微信支付零花钱刷屏了!5万额度,能花又能借
    清华集训 part1
  • 原文地址:https://www.cnblogs.com/exmyth/p/11408644.html
Copyright © 2011-2022 走看看