学习注解和了解lombok的原理

注解的定义

注解通过 @interface 关键字进行定义。

package com;
import java.lang.annotation.*;

public @interface TestSelect {
    
    
}

元注解

元注解就是用来修饰注解的。常用的元注解有@Retention和@Target。

  • @Retention注解可以理解为设置注解的生命周期。
  • @Target表示注解可以修饰哪些地方。(方法、成员变量、包等)
  • Documented这个元注解和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。

@Retention

它的取值如下:

  • RetentionPolicy.SOURCE:代表注解仅保留在源码中,并由编译器忽略。
  • RetentionPolicy.CLASS:代表注解在编译时由编译器保留,但Java虚拟机会忽略。
  • RetentionPolicy.RUNTIME:代表着标记的注解会由JVM保留,因此运行时环境可以使用它。

理解这块就得了解从 .java 文件到 class 文件再到 class 被jvm加载的过程了。下面的图描述着从.java文件到编译为class文件的过程。
在这里插入图片描述
从这里又引申出:lombok的实现原理就是在这(为什么使用了个@Data这样的注解就能有set/get等方法了,就是在这里加上去的)

@Target

它的取值如下:

  • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解。
  • ElementType.CONSTRUCTOR 可以给构造方法进行注解
  • ElementType.FIELD 可以给属性进行注解。
  • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
  • ElementType.METHOD 可以给方法进行注解。
  • ElementType.PACKAGE 可以给一个包进行注解。
  • ElementType.PARAMETER 可以给一个方法内的参数进行注解。
  • ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举。

@Inherited

Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {
    
    }
@Test
public class A {
    
    }
public class B extends A {
    
    }

注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。

@Repeatable

Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。

什么样的注解会多次应用呢?通常是注解的值可以同时取多个。

举个例子,一个人他既是程序员又是产品经理,同时他还是个画家。

@interface Persons {
    
    
    Person[]  value();
}
@Repeatable(Persons.class)
@interface Person{
    
    
    String role default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
    
    
}

注意上面的代码,@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。

什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。

我们再看看代码中的相关容器注解。

@interface Persons {
    
    
    Person[]  value();
}

按照规定,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable 注解过的注解数组,注意它是数组。

如果不好理解的话,可以这样理解。Persons 是一张总的标签,上面贴满了 Person 这种同类型但内容不一样的标签。把 Persons 给一个 SuperMan 贴上,相当于同时给他贴了程序员、产品经理、画家的标签。

我们可能对于 @Person(role=”PM”) 括号里面的内容感兴趣,它其实就是给 Person 这个注解的 role 属性赋值为 PM。

注解的属性

注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。

package com;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface TestSelect {
    
    
    int id();
    String name();
}

默认方法

package com;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface TestSelect {
    
    
    int id() default 0;
    String name() default "aaa";
}

直接写属性值

package com;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface TestSelect {
    
    
    String value();
}
package com;

public class Test {
    
    

    @TestSelect("aaa")
    private String name;
}

等同于

package com;

public class Test {
    
    

    @TestSelect(value = "aaa")
    private String name;
}

java里的注解

  • @Deprecated:用来标记过时的元素。
  • @Override:子类要复写父类中被 @Override 修饰的方法。
  • @SuppressWarnings:阻止警告的意思。
  • @SafeVarargs:参数安全类型注解。
  • @FunctionalInterface:函数式接口注解,这个是 Java 1.8 版本引入的新特性。

注解的提取

提取注解主要使用反射。
1.首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解。

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
    
    }

2.然后通过 getAnnotation() 方法来获取 Annotation 对象。或者是 getAnnotations() 方法。

 public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
    
    }
public Annotation[] getAnnotations() {
    
    }

前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解。

猜你喜欢

转载自blog.csdn.net/xiaowanzi_zj/article/details/121259878