学新通技术网

Java 注解

juejin 10 1
Java 注解

注解 Annotation

java 自带的注解

  • @Deprecated 表示当前的元素已经不推荐使用
  • @Override 表示当前方法覆盖父类的方法
  • @SuppressWarning 关闭不当的编译器警告信息

自定义注解

java 用 @interface Annotation{ }定义一个注解,一个注解是一个类,比如 @Override @Deprecated都是注解,注解相当于一种标记,在程序中加上了注解就等于为程序加上了某种标记,以后,JAVAC 编译器,开发工具和其他程序可以用反射来了解你的类以及各种元素上有无任何标记,看你有什么标记,就去干相应的事。

定义一个名为 MyTarget 的注解

public @interface MyTarget {
}

@MyTarget
class A{
}

可以为注解添加方法,加入添加 name 和 age 两个方法

public @interface MyTarget{
    String name() default "tina";
    int age();
}

//如果没有使用default设置默认值时,age 必须显式传入参数
@MyTarget(age = 18)
class A{
}
    
或者
    
// 当注解只有一个方法,没有其他方法, 或者其他方法有默认值,不要指明具体方法
@MyTarget(18)
class A{
}

除了上面例子中的 String,int 属性类型,可以定义更丰富的类型

public @interface MyTarget{
    String name() default "tina";// String 类型
    int age(); // int 类型
    String[] favorite() default {"singing","writing"};// array
    EnumTest.TrafficLamp lamp();//枚举类型  
    TestAnnotation lannotation() default @TestAnnotation(value = "aaa"); //注解类型 
    Class style() default String.class;  //默认值为 String类型的 Class类型 
}

元注解

除了上面一些注解,还有一类注解,是注解的注解,称为元注解 @Documented, @Retention, @Target, @Inherited

设置是否可被生成在 javadoc中 @Documented

被修饰注解会生成到 javadoc 中

@interface MyTarget{
}

@Documented
@interface MyDocTarget{
}

@MyTarget
@MyDocTarget
class A{
}

如果用 javadoc 生成的 javadoc, 只能看到有 @Document 注解的 MyDocTarget,看不到 MyTarget

设置注解级别 @Retention

Retention 注解有一个RetentionPolicy类型的 value, RetentionPolicy是一个枚举类型,这个枚举决定了 Retention 注解应该如何去保持,也可理解为 Rentention 搭配 RententionPolicy 使用。RetentionPolicy 有3个值:CLASS、 RUNTIMESOURCE(默认为 CLASS)

RetentionPolicy 类型 说明
SOURCE 源码级 注解只存在源码中,其功能是与编译器交互,做一些检查性的操作,如@Override@SuppressWarning。在编译的时候丢弃该注解,不会留在 class 文件中
CLASS 字节级 注解存在源码和字节码文件中,主要用于编译时生成新文件,如XML,Java文件等,但是在运行时会被丢弃。如 ButterKnife
RUNTIME 运行级 注解存在源码,字节码和 java 虚拟机中,主要用于运行时反射获取相关信息。当程序编译时,会被虚拟机保留在运行时, 所以他们可以用反射的方式读取。如 @Deprecated
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.CLASS)
public @interface MyTarget {
}

定义个一注解 @MyTarget,用 RetentionPolicy.RUNTIME 修饰

 public class TestActivity {

    @MyTarget
    public static void doSomething() {
        System.out.println("-doSomething");
    }

    public static void main(String[] args) {
        doSomething();
        Method method = null;
        try {
            method = TestActivity.class.getMethod("doSomething", null);
            if (method.isAnnotationPresent(MyTarget.class)) {
                //如果doSomething方法上存在注解 @MyTarget,则为true
                System.out.println(method.getAnnotation(MyTarget.class));
            }else{
                System.out.println("not found MyTarget!");
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

// 运行结果
上面程序打印:@cn.tina.moduler.annotation.MyTarget()
如果 RetentionPolicy 值不为 RUNTIME,则打印 not found MyTarget!

限制注解的元素种类 @Target

@Target可以修饰各种元素,比如修饰类、变量、方法等。

比如 @Override 限定该注解只能修饰方法

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

@TargetElementType 数组类型的 value

@Target(ElementType.TYPE)   // 接口、类、枚举、注解
@Target(ElementType.FIELD) // 属性、枚举的常量
@Target(ElementType.METHOD) // 方法
@Target(ElementType.PARAMETER) // 方法参数
@Target(ElementType.CONSTRUCTOR)  // 构造函数
@Target(ElementType.LOCAL_VARIABLE)// 局部变量
@Target(ElementType.ANNOTATION_TYPE)// 该注解使用在另一个注解上
@Target(ElementType.PACKAGE) // 包
@Target(ElementType.TYPE_PARAMETER) // 1.8以上
@Target(ElementType.TYPE_USE) // 1.8以上

注解的继承 @Inherited

@Inherited 可以让注解类似被继承一样,通过该注解,可以让子类类对象使用 getAnnotations() 反射获取父类被 @Inherited 修饰的注解。

本文出至:学新通技术网

标签: