Java注解

时间:2020-07-23 16:49:46   收藏:0   阅读:96

写在前面

现在的java主流框架中,注解无处不在,因此我们完全有必要搞明白注解到底是什么。如何理解注解,它到底是怎么起作用的。

注解的定义

java是这样定义注解的:Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。什么又是元数据的呢?说白了就是描述数据的数据,既然注解被称为元数据,具有描述作用,那么我们是不是可以把注解理解成标签来使用呢。我觉得学习注解,应该着重理解注解的作用是什么?在日常工作中是如何使用的即可,一般无需我们定义和解释注解,而注解解释器,也就是读取注解的类在框架中多数是隐藏起来的,除非阅读源码,否则根本看不到。
日常开发中新建Java类,我们使用class、interface比较多,而注解和它们一样,也是一种类的类型,他是用的修饰符为 @interface
格式

public @interface 注解名称{
    属性列表;
}

分类
注解可分为JDK内置注解和自定义注解

内置的注解:
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。

作用在代码的注解是

作用在其他注解的注解(或者说 元注解)是:

从 Java 7 开始,额外添加了 3 个注解:

自定义注解:
自定义注解就是自己编写的注解,而框架中所写的那些注解也可称为自定义注解,也是通过被元注解标记而写出来的注解。

注解的作用

如果说注释是写给人看的,那么注解就是写给程序看的。它更像一个标签,贴在一个类、一个方法或者字段上。它的目的是为当前读取该注解的程序提供判断依据。
要牢记,只要用到注解,必然存在三角关系:定义注解,使用注解,注解解析。如下图:
技术图片
往往我们要做的是使用注解,而注解的定义跟解析一般框架都帮我们做好了。

注解的使用

1.自定义注解怎么写?
在编写自定义注解之前,我们必须先了解元注解
以下部分摘自简书(若 | 寒),对元注解的解析做的非常不错。
上面定义中提到,元注解可以理解为注解的注解,它是作用在注解中,方便我们使用注解实现想要的功能。元注解分别有@Retention、 @Target、 @Document、 @Inherited和@Repeatable(JDK1.8加入)五种。

@Retention
Retention英文意思有保留、保持的意思,它表示注解存在阶段是保留在源码(编译期),字节码(类加载)或者运行期(JVM中运行)。在@Retention注解中使用枚举RetentionPolicy来表示注解保留时期

如果我们是自定义注解,则通过前面分析,我们自定义注解如果只存着源码中或者字节码文件中就无法发挥作用,而在运行期间能获取到注解才能实现我们目的,所以自定义注解中肯定是使用 @Retention(RetentionPolicy.RUNTIME)

@Target
Target的英文意思是目标,这也很容易理解,使用@Target元注解表示我们的注解作用的范围就比较具体了,可以是类,方法,方法参数变量等,同样也是通过枚举类ElementType表达作用类型

一般比较常用的是ElementType.TYPE类型

@Documented
Document的英文意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去。

@Inherited
Inherited的英文意思是继承,但是这个继承和我们平时理解的继承大同小异,一个被@Inherited注解了的注解修饰了一个父类,如果他的子类没有被其他注解修饰,则它的子类也继承了父类的注解。

@Repeatable
Repeatable的英文意思是可重复的。顾名思义说明被这个元注解修饰的注解可以同时作用一个对象多次,但是每次作用注解又可以代表不同的含义。

注解属性类型
注解属性类型可以有以下列出的类型

2.如何解析使用注解?
前面说到了注解如何定义,在哪使用等,其他注解的关键,是获取注解中的属性值,这才是使用注解的真正目的。前面也说到,要想使用自定义的注解,必须要使用@Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到,而获取注解的主要手段就是通过反射来获取。其中有三个主要的方法

 /**是否存在对应 Annotation 对象*/
  public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return GenericDeclaration.super.isAnnotationPresent(annotationClass);
    }

 /**获取 Annotation 对象*/
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
        Objects.requireNonNull(annotationClass);

        return (A) annotationData().annotations.get(annotationClass);
    }
 /**获取所有 Annotation 对象数组*/   
 public Annotation[] getAnnotations() {
        return AnnotationParser.toArray(annotationData().annotations);
    }    

一个小demo:
MyAnnotation.java

@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "apang";

    int num() default 99;
} 

TestAnnotation.java

@MyAnnotation(value = "注解用在类上")
public class TestAnnotation {

    @MyAnnotation()
    public void test1() {
        //使用默认值
    }

    @MyAnnotation(value = "注解用在方法上",num = 88)
    public void test2() {
        //使用自定义值
    }

}

MyAnnotationProcessor.java

public class MyAnnotationProcessor {
    public static void main(String[] args) throws Exception {
        //获取类对象
        Class clazz1 = TestAnnotation.class;
        MyAnnotation annotation = TestAnnotation.class.getAnnotation(MyAnnotation.class);
        System.out.println(annotation);
        System.out.println(annotation.value());
        System.out.println(annotation.num());
        Method[] methods = clazz1.getDeclaredMethods();
        for (Method m : methods) {
            Annotation an = m.getAnnotation(MyAnnotation.class);
            System.out.println(an);
            System.out.println(((MyAnnotation) an).value());
            System.out.println(((MyAnnotation) an).num());
        }
    }
}

输出

>>> @com.apang.annotation.MyAnnotation(value=注解用在类上, num=99)
>>> 注解用在类上
>>> 99
>>> @com.apang.annotation.MyAnnotation(value=注解用在方法上, num=88)
>>> 注解用在方法上
>>> 88
>>> @com.apang.annotation.MyAnnotation(value=apang, num=99)
>>> apang
>>> 99
评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!