元注解的作用就是负责注解其他注解
说明:
用来指明注解所修饰的目标,包括packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)取值:
值 | 作用 | 英文描述 |
---|---|---|
CONSTRUCTOR | 用于描述构造器 | |
FIELD | 用于描述域 (类的成员变量) | Field declaration. |
LOCAL_VARIABLE | 用于描述局部变量 | Local variable declaration. |
METHOD | 用于描述方法 | Method declaration. |
PACKAGE | 用于描述包 | Package declaration. |
PARAMETER | 用于描述参数 | Parameter declaration. |
TYPE | 用于描述类、接口(包括注解类型) 或enum声明 | Class, interface or enum declaration. |
CONSTRUCTOR | 构造器描述 | Constructor declaration. |
ANNOTATION_TYPE | 注解类型描述 | Annotation type declaration. |
对应代码:
public enum ElementType {
/**
* Class, interface or enum declaration.
*/
TYPE,
/**
* Field declaration.
*/
FIELD,
/**
* Method declaration.
*/
METHOD,
/**
* Parameter declaration.
*/
PARAMETER,
/**
* Constructor declaration.
*/
CONSTRUCTOR,
/**
* Local variable declaration.
*/
LOCAL_VARIABLE,
/**
* Annotation type declaration.
*/
ANNOTATION_TYPE,
/**
* Package declaration.
*/
PACKAGE
}
举例一:
Target(ElementType.TYPE)
public @interface AnnotationTest1 {
public String tableName() default "className";
}
小结:
说明这个注解被用来注解
- 类
- 接口(包括注解类型的接口)
- enum举例二:
@Target(ElementType.FIELD)
public @interface AnnotationTest2 {
}
小结:
说明这个注解被用来注解
- 类的成员变量
说明:
该注解定义了该Annotation的生命周期某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取。取值:
值 | 作用 | 英文描述 |
---|---|---|
SOURCE | 在源文件中有效(即源文件保留) | Annotation is only available in the source code. |
CLASS | 在class文件&源文件中有效(即class保留) | Annotation is available in the source code and in the class file, but nott runtime. This is the default policy. |
RUNTIME | 在运行时&源文件&class文件有效(即运行时保留) | Annotation is available in the source code, the class file and is available at runtime. |
对应代码:
public enum RetentionPolicy {
/**
* Annotation is only available in the source code.
*/
SOURCE,
/**
* Annotation is available in the source code and in the class file, but not
* at runtime. This is the default policy.
*/
CLASS,
/**
* Annotation is available in the source code, the class file and is
* available at runtime.
*/
RUNTIME
}
举例一:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
public String name() default "fieldName";
public String setFuncName() default "setField";
public String getFuncName() default "getField";
public boolean defaultDBValue() default false;
}
小结:
1. 这个注解被用来描述类的成员变量
2. 并且注解一直保留到运行时
说明:
@Documented的作用是在生成javadoc文档的时候将该Annotation也写入到文档中。举例一:
@Target(ElementType.METHOD)
@Documented
public @interface DocumentTest {
String hello();
}
使用:
public class DocumentClass {
/**
* this is method of doSomething
*/
@DocumentTest(hello = "yahaitt")
public void doSomething() {
System.out.println("do something");
}
}
结果:
@DocumentTest(hello="yahaitt")
public void doSomething()
this is method of doSomething
说明:用在注解的继承,我们自定义注解(Annotation)时,把自定义的注解标注在父类上,但是它不会被子类所继承,我们可以在定义注解时给我们自定义的注解标注一个@Inherited注解来实现注解继承。
举例一:
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InheritedTest {
String value();
}
@InheritedTest("Jadyer")
public class Parent {
@InheritedTest("JavaEE")
public void doSomething() {
System.out.println("Parent do something");
}
}
public class Child extends Parent {
}
测试:
public class Test {
public static void main(String[] args) throws SecurityException, NoSuchMethodException {
classTest();
methodTest();
}
/**
* 通过反射方式测试子类是否会继承父类中定义在类上面的注解
*/
public static void classTest(){
Class c = Child.class; //获取Child的Class对象
if (c.isAnnotationPresent(InheritedTest.class)) { //判断InheritedTest类是不是Child的父注解类
InheritedTest inheritedTest = c.getAnnotation(InheritedTest.class);
String value = inheritedTest.value();
System.out.println(value);
}
}
/**
* 通过反射方式测试子类是否会继承父类中定义在方法上面的注解
*/
public static void methodTest() throws SecurityException, NoSuchMethodException{
Class c = Child.class;
Method method = c.getMethod("doSomething", new Class[]{});
if (method.isAnnotationPresent(InheritedTest.class)) {
InheritedTest inheritedTest = method.getAnnotation(InheritedTest.class);
String value = inheritedTest.value();
System.out.println(value);
}
}
}
结果:
- 如果父类的注解是定义在类上面,那么子类是可以继承过来的
- 如果父类的注解定义在方法上面,那么子类仍然可以继承过来
- ++如果子类重写了父类中定义了注解的方法,那么子类将无法继承该方法的注解++
Java提供了三种内建注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
,由编译程序自动完成其他细节。
格式:
public @interface 注解名 {
定义体
}
注解参数支持的数据类型
- 所有基本数据类型(int,float,boolean,byte,double,char,long,short)
- String类型
- Class类型
- enum类型
- Annotation类型
- 以上所有类型的数组参数的设定
举例一:
@Target(ElementType.FIELD)//用于描述类的字段
@Retention(RetentionPolicy.RUNTIME)//保留到运行时
@Documented//打印文档时显示
public @interface FruitName {
String value() default "";//默认值是""
}
举例二:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
public enum Color{ BULE,RED,GREEN};//声明颜色枚举
Color fruitColor() default Color.GREEN;
}
举例三:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {
public int id() default -1;
public String name() default "";
public String address() default "";
}
使用:
public class Apple {
@FruitName("Apple")
private String appleName;
@FruitColor(fruitColor=Color.RED)
private String appleColor;
}
Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口主要有如下几个实现类:
所以这些我们经常用的反射手段所用到的类,都实现了AnnotatedElement接口,既然实现了此接口,那么一定有对应的实现方法供我们调用。
//如果存在这样的注解,则返回该元素的指定类型的注解,否则为空。
T getAnnotation(Class annotationClass)
//返回该程序元素上存在的所有注解。
Annotation[] getAnnotations()
//判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
boolean is AnnotationPresent(Class annotationClass)
//返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。
Annotation[] getDeclaredAnnotations()
可以看到通过反射使用的类,都可以通过指定接口得到在上面注册的注解。所以我们只需要反射得到Class、Method和Constructor,因为AnnotatedElement是Class、Method和Constructor的父接口,它们都实现了AnnotatedElement,所以,在Class、Method和Constructor中就可以使用AnnotatedElement中声明的方法来得到注解和注解内容。