zoukankan      html  css  js  c++  java
  • Java注解学习

    简介

    Java注解是JDK1.5引入的一种注释机制,它不会改变编译器的编译方式,Java编译器对包含注解和不包含注解的代码会生成相同的Java虚拟机指令。在实际应用中,注解只是一种标识,具体的操作需要借助其他工具来解析和处理

    注解语法

    注解是使用@interface来定义的,所有注解都隐式的扩展自java.lang.annotation.Annotation接口。

    如下MyFirstAnnotation是一个自定义注解,它具有两个参数name和value,默认值都为空字符串。在它的定义之上还标注了@Retention和@Target两个元注解:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface MyFirstAnnotation {
        String name() default "";
    
        String value() default "";
    }
    
    

    注解参数类型是有限制的,必须限制在以下几种类型中:

    1. 基本类型
    2. String
    3. Class
    4. enum类型
    5. 注解类型
    6. 由前面所述类型组成的数组

    例如,如果不使用以上几种,则会出现编译错误:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface MyFirstAnnotation {
        String name() default "";
    
        Integer value() default 1;//包装类型也不行,编译错误
    }
    
    

    @Target和@Retention这种作用在注解上的注解,称之为元注解。常用的元注解如下:

    1.@Target,用于标识注解可以标注的位置,接收一个ElementType[]参数。参数取值可以参考ElementType枚举类:

    public enum ElementType {
        /** 类、接口(包括注释类型)或枚举声明 */
        TYPE,
    
        /** 字段声明(包括enum常量) */
        FIELD,
    
        /** 方法声明 */
        METHOD,
    
        /** 形参声明 */
        PARAMETER,
    
        /** 构造函数声明 */
        CONSTRUCTOR,
    
        /** 局部变量声明 */
        LOCAL_VARIABLE,
    
        /** 注解类型声明 */
        ANNOTATION_TYPE,
    
        /** 包声明 */
        PACKAGE,
    
        /**
         * 类型参数声明
         *
         * @since 1.8
         */
        TYPE_PARAMETER,
    
        /**
         * 任何类型名称
         *
         * @since 1.8
         */
        TYPE_USE
    }
    

    当指定的@Target和注解的使用位置不匹配时就会出现编译错误,如下所示,@Target(ElementType.METHOD)表示MyFirstAnnotation注解只能用来标注方法,标注在类上就出现编译错误:

    //编译错误
    @MyFirstAnnotation
    public class Demo {
    
        //正确
        @MyFirstAnnotation
        public void doSomeThing(){
        }
    
    }
    

    2.@Retention,用于标识注解可以保留多久,接收一个RetentionPolicy参数,参数取值可以参考RetentionPolicy枚举类:

    public enum RetentionPolicy {
        /**
         * 表示注解只会存在于.java的源代码文件中,不会保留到编译后的.class文件中
         */
        SOURCE,
    
        /**
         * 表示注解可以保留到.class文件中,但是不会被Java虚拟机所加载
         */
        CLASS,
    
        /**
         * 表示注解可以保留到.class文件中,并由虚拟机加载
         */
        RUNTIME
    }
    

    3.@Documented,表示这个注解能出现在javadoc中。

    4.@Inherited,表示当这个注解用于一个类的时候,能够自动的被它的子类继承。

    5.@Repeatable,表示这个注解可以在同一个位置应用多次。

    默认情况下,同一个位置添加多个重复注解会有编译错误:

    public class Demo {
        //编译错误
        @MyFirstAnnotation(name = "张三")
        @MyFirstAnnotation(name = "李四")
        @MyFirstAnnotation(name = "王五")
        public void doSomeThing(){
        }
    
    }
    

    可以通过添加@Repeatable元注解来使@MyFirstAnnotation能重复使用。
    首先需要创建一个容器注解@MyFirstAnnotations,容器注解@MyFirstAnnotations必须要有一个参数value,并且其类型为MyFirstAnnotation[]:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface MyFirstAnnotations {
        MyFirstAnnotation[] value();
    }
    
    

    然后添加@Repeatable注解,并指定容器注解。

    @Repeatable(MyFirstAnnotations.class)
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface MyFirstAnnotation {
        String name() default "";
    
        String value() default "";
    }
    

    关于注解的使用需要注意,注解参数是不能为null的,默认值也是不能为null

    自定义注解测试

    定义注解@RepeatMethod,包含int类型参数value。

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface RepeatMethod {
    
        int value() default 1;
    
    }
    
    

    在doSomeThing方法上应用注解。如果要指定的注解参数为value,并且没有指定其他的参数值时,可以采用简写的方式,省略参数名和等号。

    public class Demo {
        @RepeatMethod(5)
        public void doSomeThing(){
            System.out.println("----注解测试----");
        }
    }
    
    
    

    通过反射获取注解信息,然后做对应的处理,如假设@RepeatMethod注解的作用是重复调用被标注的方法,参数value是指定重复调用方法的次数:

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class MyDemo {
        public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException {
            Class cla = Demo.class;
            Method[] methods = cla.getMethods();
            Object demo = cla.newInstance();
            for (Method method : methods){
                //判断方法上是否有标注@RepeatMethod注解
                if(method.isAnnotationPresent(RepeatMethod.class)){
                    //获取RepeatMethod注解的参数值
                    RepeatMethod repeatMethod = method.getAnnotation(RepeatMethod.class);
                    for (int i = 0;i < repeatMethod.value(); i++)
                    method.invoke(demo, null);
                }
            }
        }
    }
    
    

    输出结果:

    ----注解测试----
    ----注解测试----
    ----注解测试----
    ----注解测试----
    ----注解测试----
    
  • 相关阅读:
    poj.1703.Find them, Catch them(并查集)
    uva.10020 Minimal coverage(贪心)
    Hdu.1325.Is It A Tree?(并查集)
    1455.Solitaire(bfs状态混摇)
    hdu.1430.魔板(bfs + 康托展开)
    hdu.1254.推箱子(bfs + 优先队列)
    hihoCoder挑战赛11.题目4 : 高等理论计算机科学(LCA)
    Codeforces Round #302 (Div. 2).C. Writing Code (dp)
    hdu.1198.Farm Irrigation(dfs +放大建图)
    hdu.1111.Secret Code(dfs + 秦九韶算法)
  • 原文地址:https://www.cnblogs.com/seve/p/14441203.html
Copyright © 2011-2022 走看看