Hao's Blog
Java注解的简单记录

什么是注解

注解较多的解释是一种元数据(描述数据的数据),其实相当于一种标签.作用就是用来替代XML配置文件,在后期的很多框架里配置基本以注解的形式存在

注解的定义

注解使用 @interface 关键词进行定义,例如

@interface TestAnnotation {}

注意注解也可以加修饰符,但是只能使用pulbic和abstract

注解的属性

@interface TestAnnotation5 {
    String name();  //这就是注解的属性,与常规类属性不同的是需要在属性名后加括号
    int id() default 100; //这是为属性设置默认值,如果在使用注解时未对该属性赋值,那么就为默认值
    boolean value(); //如果参数的名字为value那么赋值的时候可以不写value=
}

元注解

元注解是一种基本注解,可以使用在注解上.
元注解有
@Retention 保留期

RetentionPolicy.SOURCE, 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视
RetentionPolicy.CLASS, 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中
RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取

@Documented
在生成文档是时候可以将被注解的元素写到javadoc文档中

@Target 可以指定被注解的注解使用的位置

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

@Inherited 继承
注解本身是没有继承的.使用**@Inherited** 注解过的注解去注解一个超类father时,如果它的子类son没有被任何注解应用,其继承father的子类son就继承了超类father的注解

@Inherited
@Retention(RetentionPolicy.Source)
@TestAnnotation2 {}

//超类father

@TestAnnotation2
public class Father{}

//子类son继承father,就拥有了father的注解@Retention(RetentionPolicy.Source)
public class Son extends Father {}

@Repeatable 可重复(JDK8新特性)
重复使用注解JDK8之前解决方案

@interface person {
    String role();
}

@interface persons {
    person[] value();
}

public class TestAnnotation3 {
    @persons({@person(role = "singer"), @person(role = "dancer")})
    public void action() {
    }
}

有了 @Repeatable 之后,增加了可读性

@interface persons {
    person[] value(); //规定这个属性的名字必须为value
}

@Repeatable(persons.class) //容器注解
@interface person {
    String role();
}

//使用
public void TestAnnotation4 {
    @person(role = "singer")
    @person(role = "dancer")
    public void action() {}
}

Java的内置注解

@Deprecated 废弃
@Override 重写
@SuppressWarnings 压制警告

以下两种目前我搞不太懂
@SafeVarargs 参数安全类型注解
@FunctionalInterface 函数式接口注解

注解的读取

读取注解的内容需要依赖反射了.

### 注意注解的默认保留策略仅仅是RetentionPolicy.CLASS,如果想要在运行时读取注解,那么就需要申明保留策略为RetentionPolicy.RUNTIME

判断是否使用了某个注解的方法

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

例子:

@Retention(RetentionPolicy.RUNTIME) //注意一定要设置保留策略到RUNTIME,否则运行时注解就没了

public @interface MyAnnotation {
    int id();
    String name();
}

//使用注解测试
@MyAnnotation(id = 5, name = "zs")
public class Test {
    public void main(String args[]) {
        //获取要检测是否使用注解的类的Class,这个不仅仅局限于类,而是取决于注解的位置,如果在方法上,则要获取方法,属性上则获取属性调用该方法,依次..
        Class clazz = Test.class;
        //
        boolean status = clazz.isAnnotationPresent(MyAnnotation.class);
        System.out.println(status); //输出true
    }
}

获取Annotation对象

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

public Annotation[] getAnnotations() {}
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2 {
    int id() default 2;
    String value();
}

//测试,以类上的注解为例,当然属性,方法上也适用
@MyAnnotation2("ls")
public class Test2 {
    public void main(String[] args) {
        Class clazz = Test2.class;
        boolean status = clazz.isAnnotationPresent(MyAnnotation2.class);
        if(status) {
            MyAnnotation2 m2 = (MyAnnotation2) clazz.getDeclaredAnnotation(MyAnnotation2.class);
            System.out.println(m2.id());  //输出2
            System.out.println(m2.value()); //输出ls
        }
    }
}