Annotation——自定义注解
Java中提供了 Annotation 功能,该功能可用于类,构造方法,成员变量,方法。参数等的声明中。该功能不会影响程序的运行,但是会对编译器警告等辅助工具产生影响。
定义 Annotation 类型
在定义 Annotation 类型时,需要用到用来定义接口的 interface 关键字,但需要在 interface 关键字前面加一个 “ @ ” 符号,即定义 Annotation 类型的关键字为@interface 。
public @interface MyAnnotation {
}
这样就是定义了一个 Annotation 类型。上面定义的 Annotation 类型未包含任何成员,为 Annotation 类型添加成员。
public @interface MyAnnotation {
String name();
Class type();
}
在为 Annotation 类型定义成员时,也可以为成员设置默认值。
public @interface MyAnnotation {
String name() default "默认值";
Class type() default void.class;
}
访问 Annotation 信息
可以通过反射注解,来访问 Annotation 信息,想要反射注解还需要了解一下元注解。元注解就是为其他注解做注解,也就是注解的注解。元注解有四个,常用的有两个 @Target 和 @Retention 。
@Target
在定义 Annotation 时,可以通过 @Target 来设置 Annotation 适用的程序元素种类,如果为设置 @Target ,则表示适用于所有程序元素。枚举类 ElementType 中的枚举常量用来设置 @Target。
枚举类 ElementType 中的枚举常量
枚举常量 | 说明 |
---|---|
ANNOTATION_TYPE | 表示用于 Annotation 类型 |
TYPE | 表示用于类,接口和枚举,以及Annotation 类型 |
CONSTRUCTOR | 表示用于构造方法 |
FIELD | 表示用于成员变量和枚举变量 |
METHOD | 表示用于方法 |
PARAMETER | 表示用于参数 |
LOCAL_VARIABLE | 表示用于局部变量 |
PACKAGE | 表示用于包 |
@Retention
通过设置 Annotation 类型的 @Retention ,可设置 Annotation 的有效范围。枚举类 RetentionPolicy 中的枚举常量用来设置 @Retention ,如果未设置 @Retention ,Annotation 的有效范围为枚举常量 CLASS 表示的范围。
枚举类 RetentionPolicy 中的枚举常量
枚举常量 | 说明 |
---|---|
SOURCE | 表示不编译 Annotation 到类文件中,有效范围最小 |
CLASS | 表示编译 Annotation 到类文件中,但是在运行时不加载 Annotation 到JVM中 |
RUNTIME | 表示在运行时加载 Annotation 到JVM中,有效范围最大 |
之前反射的三个类 Constructors (构造方法类),Field (成员属性类),Methods (成员方法类)都提供的可以反射注解的方法。
要想将注解反射出来有个前提,需要将 @Retention 设置成 RUNTIME 。
实例
首先创建一个Dome类,为其添加几个属性。
public class Dome {
public String name;// 名称
public double price;// 价格
public String produced;// 厂商
}
然后定义一个 Annotation 类型,为这些属性添加注释。
public @interface MyAnnotation {
String remkras() default "";//备注
boolean enable() default true;//属性是否启用,默认true
}
然后回到Dome类中,为属性添加注解。将属性 produced 厂商设置一个过时的注解,不启用。
public class Dome {
@MyAnnotation(remkras = "名称")
public String name;// 名称
@MyAnnotation(remkras = "价格")
public double price;// 价格
@Deprecated
@MyAnnotation(remkras = "厂商", enable = false)//不启用
public String produced;// 厂商
}
现在就来反射这些注解,创建一个新的类Study2
public class Study2 {
public static void main(String[] args) {
Class c = Dome.class;//创建class对象
Field fl[] = c.getDeclaredFields();//获取所有属性
for(Field f:fl) {
if(f.isAnnotationPresent(MyAnnotation.class)) {
//判断注解是否被MyAnnotation注解过
System.out.println(f.getName()+"被注解过");
}
}
}
}
注意:
需要为 MyAnnotation 添加 @Retention 与 @Target 设置,否则运行不出来。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
完整代码
MyAnnotation:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String remkras() default "";//备注
boolean enable() default true;//属性是否启用,默认true
}
Dome:
public class Dome {
@MyAnnotation(remkras = "名称")
public String name;// 名称
@MyAnnotation(remkras = "价格")
public double price;// 价格
@Deprecated
@MyAnnotation(remkras = "厂商", enable = false)//不启用
public String produced;// 厂商
}
Study2:
import java.lang.reflect.Field;
public class Study2 {
public static void main(String[] args) {
Class c = Dome.class;// 创建class对象
Field fl[] = c.getDeclaredFields();// 获取所有属性
for (Field f : fl) {
if (f.isAnnotationPresent(MyAnnotation.class)) {
// 判断注解是否被MyAnnotation注解过
System.out.println(f.getName() + "被注解过");
MyAnnotation m = f.getAnnotation(MyAnnotation.class);// 创建MyAnnotation对象,获取注解
System.out.print(f.getName() + "属性的注解内容:");
System.out.print("备注=" + m.remkras() + " , ");// 获取备注内容
System.out.println("属性是否启用=" + m.enable());// 获取属性是否启用
}
}
}
}
运行截图: