注解

JDK 5开始,Java支持注解。
注解,Annotation,是一种代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取并执行,而且不改变原有的逻辑。

注解可以用于:生成文档、编译检查、代码分析。

基本注解

@Override

方法重写、方法覆盖

@Deprecated

已过时

@SuppressWarnings

压制编译器警告

@FunctionalInterface

Java8新增。Java 8规定,如果接口中只有一个抽象方法,就是函数式接口(类方法和默认方法不限),此注解用来指定“必须是函数式接口”

@SafeVarargs

Java7新增。将不带泛型的对象(如List[])赋给带泛型变量时,会发生堆污染(Heap pollution),此注解用来压制堆污染。

package ah.annotation;
import java.util.ArrayList;
import java.util.List;
class A {
    @Deprecated
    public void info() {
        System.out.println("Deprecated:info");
    }
    public void warnings() {
        @SuppressWarnings("unused")
        String s = null;
        @SuppressWarnings("all")
        List myList = new ArrayList();
    }
    @SafeVarargs
    public static void faultyMethod(List<String>... listStrArray) {
        // Java 7新增注解
        // Varargs:可变参数
        // 形参【List<String>...】相当于数组,但Java不支持泛型数组,会将其当做List[]处理
        // 将不带泛型的对象(如List[])赋给带泛型变量时,会发生堆污染(Heap pollution)
        // 因此泛型可变参数容易导致堆污染
    }
}
@FunctionalInterface
interface B {
    // Java 8规定,如果接口中只有一个抽象方法,就是函数式接口(类方法和默认方法不限)
    // 此注解用来指定“必须是函数式接口”
    static void m1() {}
    default void m2() {}
    // 只一个抽象方法
    void m3();
    // 再一个抽象方法就出错: is not a functional interface
    // void m4();
}
public class TestBaseAnnotation {
    public static void main(String[] args) {
        new A().info();
    }
}
package ah.annotation;
import java.util.ArrayList;
import java.util.List;
class A {
    @Deprecated
    public void info() {
        System.out.println("Deprecated:info");
    }
    public void warnings() {
        @SuppressWarnings("unused")
        String s = null;
        @SuppressWarnings("all")
        List myList = new ArrayList();
    }
    @SafeVarargs
    public static void faultyMethod(List<String>... listStrArray) {
        // Java 7新增注解
        // Varargs:可变参数
        // 形参【List<String>...】相当于数组,但Java不支持泛型数组,会将其当做List[]处理
        // 将不带泛型的对象(如List[])赋给带泛型变量时,会发生堆污染(Heap pollution)
        // 因此泛型可变参数容易导致堆污染
    }
}
@FunctionalInterface
interface B {
    // Java 8规定,如果接口中只有一个抽象方法,就是函数式接口(类方法和默认方法不限)
    // 此注解用来指定“必须是函数式接口”
    static void m1() {}
    default void m2() {}
    // 只一个抽象方法
    void m3();
    // 再一个抽象方法就出错: is not a functional interface
    // void m4();
}
public class TestBaseAnnotation {
    public static void main(String[] args) {
        new A().info();
    }
}

自定义注解

使用@interface定义注解。

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotation {
    String id();
    String name() default "A";
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotation {
    String id();
    String name() default "A";
}

注解本质就是接口,接口的属性本质就是抽象方法。

// 将一个自定义注解反编译(javap MyAnnotation.class)后会得到如此代码
public interface MyAnnotation extends java.lang.annotation.Annotation {
  public abstract java.lang.String id();
  public abstract java.lang.String name();
}
// 将一个自定义注解反编译(javap MyAnnotation.class)后会得到如此代码
public interface MyAnnotation extends java.lang.annotation.Annotation {
  public abstract java.lang.String id();
  public abstract java.lang.String name();
}

元注解:用于描述注解的注解

@Target:注解能作用的位置

|--@Target(ElementType.TYPE):作用于类、接口、枚举
|--@Target(ElementType.METHOD):作用于方法
|--@Target(ElementType.FIELD):作用于成员变量
|--@Target(value = { ElementType.TYPE, ElementType.METHOD }):作用于多处

@Retention:注解被保留的阶段(retention,保留)

|--@Retention(RetentionPolicy.RUNTIME):保留到运行时。
|--|--自定义注解一般都取此值。注解信息会保留到class文件中,可以通过反射获取注解信息。

@Documented:注解是否被抽取到API文档中

@Inherited:被注解的类如果有子类的话,注解会被继承

注解的属性

(1)注解的属性以无参数方法的形式声明;
(2)返回值只能是:基本类型、字符串、枚举、注解,或其数组{数组赋值时用大括号,如果就一个值,大括号可以省略}。
(3)可以指定默认值;
(4)如果只有一个属性value,则可以直接赋值
|--|--如:@SuppressWarnings("all")

package ah.annotation;
import java.lang.annotation.*;
//枚举类型
enum MyEnum {
    e1, e2;
}
// ========================
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2 {
    // 属性的返回值
    int prop1();
    String prop2();
    MyEnum prop3();
    Override prop4();
    // =============
    int[] prop11();
    String[] prop12();
    MyEnum[] prop13();
    Override[] prop14();
}
// ========================
// 测试各种赋值操作用的注解
@interface MyAnn0 {
    // 无属性的注解(如@Override)
}
@interface MyAnn1 {
    int prop();// 单属性的注解
}
@interface MyAnn2 {
    // 多属性的注解
    int prop1();
    int prop2();
}
@interface MyAnn_default {
    // 默认值
    int prop() default 1;
}
@interface MyAnn_value {
    // 特殊属性value,如果仅1个属性,且叫value,赋值时可省略属性名
    int value();
}
@interface MyAnn_type {
    String s();
    MyEnum e();
    Override a();
    int[] arr();
    int[] arr2();
}
// ========================
// 用于注解的类
class UseAnno {
    @MyAnn0
    void m1() {}
    @MyAnn1(prop = 1)
    void m2() {}
    @MyAnn2(prop1 = 1, prop2 = 2)
    void m3() {}
    @MyAnn_default
    void m4() {}
    @MyAnn_value(1)
    void m5() {}
    @MyAnn_type(s = "A", e = MyEnum.e1, a = @Override, arr = { 1, 2 }, arr2 = 3)
    void m6() {}
}
package ah.annotation;
import java.lang.annotation.*;
//枚举类型
enum MyEnum {
    e1, e2;
}
// ========================
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2 {
    // 属性的返回值
    int prop1();
    String prop2();
    MyEnum prop3();
    Override prop4();
    // =============
    int[] prop11();
    String[] prop12();
    MyEnum[] prop13();
    Override[] prop14();
}
// ========================
// 测试各种赋值操作用的注解
@interface MyAnn0 {
    // 无属性的注解(如@Override)
}
@interface MyAnn1 {
    int prop();// 单属性的注解
}
@interface MyAnn2 {
    // 多属性的注解
    int prop1();
    int prop2();
}
@interface MyAnn_default {
    // 默认值
    int prop() default 1;
}
@interface MyAnn_value {
    // 特殊属性value,如果仅1个属性,且叫value,赋值时可省略属性名
    int value();
}
@interface MyAnn_type {
    String s();
    MyEnum e();
    Override a();
    int[] arr();
    int[] arr2();
}
// ========================
// 用于注解的类
class UseAnno {
    @MyAnn0
    void m1() {}
    @MyAnn1(prop = 1)
    void m2() {}
    @MyAnn2(prop1 = 1, prop2 = 2)
    void m3() {}
    @MyAnn_default
    void m4() {}
    @MyAnn_value(1)
    void m5() {}
    @MyAnn_type(s = "A", e = MyEnum.e1, a = @Override, arr = { 1, 2 }, arr2 = 3)
    void m6() {}
}