• 注解


    注解(也被称为元数据)。

    Java SE内置了三种,定义在java.lang中的注解:

    @Override,表示当前的方法定义将覆盖超类中的方法。

    @Deprecated,如果使用了注解为它的元素,编译器会发出警告。

    @Suppress Warnings,关闭不当的编译器警告信息。

    元注解,专职负责注解其他的注解:

    @Target

    @Retention

    @Documented

    @Inherited

    一、Java中的常见注解

    1)JDK注解
    JDK注解一共分为三类:


    JDK注解.png

    案例:
    我们先新建一个接口people,如下:

    public interface people {
        public String name();
        public int age();
        public void work();
    }

    然后再建一个类Child实现类people这个接口,并实现该类的方法:

    public class Child implements people {
        @Override
        public String name() {
            return null;
        }
    
        @Override
        public int age() {
            return 0;
        }
    
        @Override
        public void work() {
    
        }

    看到这里,我们发现这里的所有方法都会加上一个@Override标记,它告诉我们,同时也告诉编译器我们的这些方法肯定覆盖了类people里面的方法的。假如说,我现在把类people里面的某一个方法注释掉:

    //public String name();

    再看类Child里面的name方法就会报错。这样,以后大家看到@Override的时候就能想到这个方法是覆盖了某个接口的方法的。

    然后,我们回过头来看类people里面有一个work的方法。这里我们可以理解为人是要工作的,但是并不是所有的人都在工作,那么怎么办呢?如果说这个接口正在用,我们不能删除这个方法,这个时候我们就可以这样:

    @Deprecated
    public void work();

    @Deprecated标记就表明这个方法已经过时了,在实际中,它又有什么样的应用场景呢?我们在建一个测试类:

    public class Test {
        public void work() {
            people people=new Child();
    !        people.work();
        }
    }

    这个时候我们会发现myeclipse会给一个警告,并且在work中间出现一个破折号,意思就是这个方法已经过时了。那么问题来了,虽然这个方法过时了,但是我们就是那么傲娇,一定要用它,怎么办呢?只需要这样:

    public class Test {
        @SuppressWarnings("deprecation")
        public void work() {
            people people=new Child();
            people.work();
        }
    }

    这样我们就忽略了这个警告。@SuppressWarnings("deprecation")就表示我们忽略了deprecation这样的一个警告。

    2)Java第三方注解


    第三方注解.png

    二、注解的分类

    1)按照运行机制划分:
    【源码注解→编译时注解→运行时注解】

    源码注解:只在源码中存在,编译成.class文件就不存在了。

    编译时注解:在源码和.class文件中都存在。像前面的@Override、@Deprecated、@SuppressWarnings,他们都属于编译时注解。

    运行时注解:在运行阶段还起作用,甚至会影响运行逻辑的注解。像@Autowired自动注入的这样一种注解就属于运行时注解,它会在程序运行的时候把你的成员变量自动的注入进来。

    2)按照来源划分:
    【来自JDK的注解——来自第三方的注解——自定义注解】

    3)元注解:
    元注解是给注解进行注解,可以理解为注解的注解就是元注解。

    三、自定义注解

    我们分四步来解析自定义注解:
    自定义注解的语法要求:

    @Target({ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Description {
        String desc();
        String author();
        int age() default 18;
    }

    首先我们要明确这不是一个接口,它是使用@interface关键字定义的一个注解。
    然后我们看下面的几个方法,String desc();虽然它很类似于接口里面的方法,其实它在注解里面只是一个成员变量(成员以无参无异常的方式声明),int age() default 18;(成员变量可以用default指定一个默认值的)。
    最后我们要知道:
    ①.成员类型是受限制的,合法的类型包括基本的数据类型以及String,Class,Annotation,Enumeration等。
    ②.如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=)。
    ③.注解类可以没有成员,没有成员的注解称为标识注解。

    元注解:

    有没有发现上面那段代码有一个没有说呢?没错,它们就是我们所说的元注解:

    @Target({ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented

    我们先看第一行:@Target是这个注解的作用域,ElementType.METHOD是这个注解的作用域的列表,METHOD是方法声明,除此之外,还有:
    CONSTRUCTOR(构造方法声明),FIELD(字段声明),LOCAL VARIABLE(局部变量声明),METHOD(方法声明),PACKAGE(包声明),PARAMETER(参数声明),TYPE(类接口)

    第二行:@Retention是它的生命周期,前面不是说注解按照运行机制有一个分类嘛,RUNTIME就是在运行时存在,可以通过反射读取。除此之外,还有:
    SOURCE(只在源码显示,编译时丢弃),CLASS(编译时记录到class中,运行时忽略),RUNTIME(运行时存在,可以通过反射读取)

    第三行:@Inherited是一个标识性的元注解,它允许子注解继承它。

    第四行:@Documented,生成javadoc时会包含注解。

    使用自定义注解:
    使用注解的语法:
    @<注解名>(<成员名1>=<成员值1>,<成员名1>=<成员值1>,...)
    案例:

        @Description(desc="i am Color",author="boy",age=18)
        public String Color() {
            return "red";
        }

    这里的Description是我们刚才在自定义注解语法要求里面定义的注解噢,然后我们可以给它的每一个成员变量赋值,注意数据类型。值得注意的是,因为我们前面定义的作用域是在方法和类接口上,所以这个注解在Color()方法上使用是没问题的。

    解析注解
    概念:
    通过反射获取类 、函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑。

    准备工作:


    Description类.png

    Child类.png

    接下来,我们就开始测试了:

    public class ParseAnn {
        public static void main(String[] args) {
            try {
                // 使用类加载器加载类
                Class c = Class.forName("com.test.Child");
                // 找到类上面的注解
                boolean isExist = c.isAnnotationPresent(Description.class);
                // 上面的这个方法是用这个类来判断这个类是否存在Description这样的一个注解
                if (isExist) {
                    // 拿到注解实例,解析类上面的注解
                    Description d = (Description) c.getAnnotation(Description.class);
                    System.out.println(d.value());
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    输出的结果:
    i am class annotation
    可以看到,我们成功的解析了Child类上面的注解。

    接下来,我们继续解析方法上的注解:

                //获取所有的方法
                Method[] ms = c.getMethods();
                // 遍历所有的方法
                for (Method m : ms) {
                    boolean isExist1 = m.isAnnotationPresent(Description.class);
                    if (isExist1) {
                        Description d1=m.getAnnotation(Description.class);
                        System.out.println(d1.value());
                    }
                }

    输出的结果:
    i am class annotation
    i am method annotation
    可以看到,我们成功的解析了方法上面的注解。

                //另一种解析方法
                for (Method m : ms) {
                    //拿到方法上的所有的注解
                    Annotation[] as=m.getAnnotations();
                    for (Annotation a : as) {
                        //用二元操作符判断a是否是Description的实例
                        if (a instanceof Description) {
                            Description d=(Description) a;
                            System.out.println(d.value());
                        }
                    }
                }

    也可以得到上面的效果。

    此时,如果把Description类里面的元注解改一下,比如:
    @Retention(RetentionPolicy.RUNTIME)→@Retention(RetentionPolicy.SOURCE),再运行程序,结果会成怎样呢?如果改成CLASS呢?读者们要不要试一试?

    如果看过我写的《谈谈JAVA反射机制》——Class类的动态加载的读者,仔细想一下我们这个环境,就知道为什么了。



    作者:locality
    链接:http://www.jianshu.com/p/b560b30726d4
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    CSU 1505: 酷酷的单词【字符串】
    HDU 2036 改革春风吹满地【计算几何/叉乘求多边形面积】
    HDU 2034 人见人爱A-B【STL/set】
    HDU 2031 进制转换
    HDU 1020 Encoding【连续的计数器重置】
    HDU 1999 不可摸数【类似筛法求真因子和】
    动态规划总结
    CSU 1785: 又一道简单题
    CSU 1779: 错误的算法【矩阵/模拟】
    CSU 1777: 大还是小?【模拟/后导0】
  • 原文地址:https://www.cnblogs.com/zyfzyfzyf/p/7611832.html
Copyright © 2020-2023  润新知