Annotation 注解说明
Java 中提供了 Anmotation 注解功能,该功能可用于类、构造方法、成员变量、成员方法、参数、字段等的声明中。用来提供额外的信息或配置。
注解的定义
- 注解的定义:
使用@interface
关键字定义一个注解,这个关键字的隐含意思是继承java.lang.annotation.Annotation
接口。
定义一个没有任何成员的Annotation 类型
,这样的 Annotation 类型被称为 marker annotation。
public @interface NoMemberAnnotation {
}
定义一个只包含一个成员的 Annotation 类型
public @interface OneMemberAnnotation {
String value();
}
String: 成员类型。可用的成员类型有 String、Class、primitive、enumerated 和 annotation,以及所列类型的数组。
定义一个包含多个成员的 Annotation 类型
public @interface MoreMemberAnnotation {
String describe();
Class type();
}
注解可以包含成员变量,也可以有默认值。
public @interface MyAnnotation {
String value() default "";
int count() default 0;
}
元注解
- 元注解是可以注解到注解上的注解
- 元标签有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。
@Target
- Target 是目标的意思,@Target 指定了注解运用的地方。
- 在定义 Annotation 类型时,还可以通过 Annotation 类型@Target 来设置 Annotation 类型适用的程序元素种类。如果未设置@Target,则表示适用于所有程序元素。枚举类 ElementType 中的枚举常量用来设置@Targer
枚举常量 说明
----------------------------------------------------------------
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
实例1
@Target()// 用于构造方法、字段、方法和参数
//@Target( {ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
public @interface Constructor_Annotation {
String value() default "默认构造方法"; // 定义一个具有默认值的String型成员
}
@Retention
- Retention 的英文意为保留期的意思。说明了这个注解的的存活时间。
- 通过 Annotation 类型@Retention 可以设置 Annotation 的有效范围。枚举类 RetentionPolicy 中的枚举常量用来设置@Retention。如果未设置@Retention,Amotation 的有效范围为枚举常量CLASS 表示的范围。
枚举常量 说明
SOURCE 表示不编译 Annotation 到类文件中,有效范围最小
CLASS 表示编译 Annotation 到类文件中,但是在运行时不加载 Anmotation 到JVM中
RUNTIME 表示在运行时加载 Annotation 到JVM 中,有效范围最大
实例
@Retention(RetentionPolicy.RUNTIME)// 在运行时加载Annotation到JVM中
public @interface Field_Method_Parameter_Annotation {
String describe(); // 定义一个没有默认值的String型成员
Class type() default void.class; // 定义一个具有默认值的Class型成员
}
@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 这个注解。
@Documented
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。
@Repeatable
Repeatable 自然是可重复的意思。
举个例子,一个人他既是程序员又是产品经理,同时他还是个画家。
@interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
@interface Person{
String role default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}
注解的应用
多个成员
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TestAnnotation {
int id();
String msg();
}
@TestAnnotation(id=3,msg="hello annotation")
public class Test {
}
有默认值
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TestAnnotation {
public int id() default -1;
public String msg() default "Hi";
}
//TestAnnotation 中 id 属性默认值为 -1,msg 属性默认值为 Hi。
//它可以这样应用。
@TestAnnotation()//因为有默认值,所以无需要再在 @TestAnnotation 后面的括号里面进行赋值了,这一步可以省略。
public class Test {}
只有一个成员
如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内。
@interface Check {
String value();
}
@Check("hi")
int a;
这和下面的效果是一样的
@Check(value="hi")
int a;
没有任何成员
public @interface Perform {}
//应用这个注解的时候,括号都可以省略。
@Perform
public void testMethod(){}
完整例子
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String value() default "";
int count() default 0;
}
@MyAnnotation(value = "example", count = 5)
class TestDemo {
@MyAnnotation(value ="field")
//或 @MyAnnotation("field")
private String name;
@MyAnnotation(value ="method")
//或 @MyAnnotation("method")
public void myMethod() {
// 方法体
System.out.println("myMethod");
}
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
TestDemo obj = new TestDemo();
// 获取类上的注解
MyAnnotation classAnnotation = obj.getClass().getAnnotation(MyAnnotation.class);
System.out.println("====获取类上的注解====");
System.out.println(classAnnotation.value());
System.out.println(classAnnotation.count());
// 获取字段上的注解
Field field = obj.getClass().getDeclaredField("name");
MyAnnotation fieldAnnotation = field.getAnnotation(MyAnnotation.class);
System.out.println("====获取字段上的注解====");
System.out.println(fieldAnnotation.value());
// 获取方法上的注解
Method method = obj.getClass().getMethod("myMethod");
MyAnnotation methodAnnotation = method.getAnnotation(MyAnnotation.class);
System.out.println("====获取方法上的注解====");
System.out.println(methodAnnotation.value());
}
}
//运行结果
====获取类上的注解====
example
5
====获取字段上的注解====
field
====获取方法上的注解====
method