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){
    }
    
  • 相关阅读:
    POJ 1703 Find them, Catch them
    POJ 2236 Wireless Network
    POJ 2010 Moo University
    POJ 2184 Cow Exhibition
    POJ 3280 Cheapest Palindrome
    POJ 3009 Curling 2.0
    POJ 3669 Meteor Shower
    POJ 2718 Smallest Difference
    POJ 3187 Backward Digit Sums
    POJ 3050 Hopscotch
  • 原文地址:https://www.cnblogs.com/exmyth/p/11408644.html
Copyright © 2011-2022 走看看