Java注解

注解语法

public @interface annationName{
    
}

元注解

可以添加到注解上的注解,是一种基本注解

元注解有@Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。

@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 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @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 后面括号中的类相当于一个容器注解。

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

注解的属性

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

注意:注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组

注解中属性可以有默认值,默认值需要用 default 关键值指定。比如

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Annation1 {
    String value();
    int age() default 0;
}

java预置的注解

Deprecated

标注过时的方法、过时的类、过时的成员变量
public class Annation2 {
    @Deprecated
    public void say1() {
        System.out.println("say hello1");
    }

    public void say2() {
        System.out.println("say hello2");
    }
    public static void main(String[] args){
     Annation2 annation2 = new Annation2();
     annation2.say1();
     annation2.say2();
    }
}

say1()方法调用时会显示一条划线,表示方法已过时,但不影响调用

@Override

提示子类要复写父类中被 @Override 修饰的方法

@SuppressWarnings

阻止警告的意思。之前说过调用被 @Deprecated 注解的方法后,编译器会警告提醒,而有时候开发者会忽略这种警告,他们可以在调用的地方通过 @SuppressWarnings 达到目的

@SafeVarargs

@FunctionalInterface

函数式接口注解,这个是 Java 1.8 版本引入的新特性。函数式编程很火,所以 Java 8 也及时添加了这个特性。

函数式接口 (Functional Interface) 就是一个具有一个方法的普通接口

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

注解的提取

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

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

然后通过 getAnnotation() 方法来获取 Annotation 对象。

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

或者是 getAnnotations() 方法。

public Annotation[] getAnnotations() {}

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

如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法了。比如

@Annation1(value = "123",age = 12)
public class TestAnnation1 {
    /**
     * 反射获取注解
     * @param args
     */
    public static void main(String[] args){
           boolean hasAnnation = TestAnnation1.class.isAnnotationPresent(Annation1.class);
           if (hasAnnation) {
               Annation1 annation1 = TestAnnation1.class.getAnnotation(Annation1.class);
               System.out.println("value="+annation1.value());
               System.out.println("age="+annation1.age());
           }
    }
}
上一篇:Android自定义注解


下一篇:注解控件仓库