java提供了四种元注解,专门用来注解其他的注解
@Documented –注解是否将包含在JavaDoc中
@Retention –什么时候使用该注解,即该注解的生命周期。
RetentionPolicy.SOURCE 只在源码显示,编译时丢弃
比如override注解
RetentionPolicy.CLASS 编译时记录到class中,运行时忽略
RetentionPolicy.RUNTIME 运行时存在,可以通过反射读取
@Target -注解用于什么地方,即该注解的作用域,作用域可以同时存在多个
ElementType.TYPE(类,接口,枚举)
ElementType.FIELD(字段声明)
ElementType.METHOD(方法声明)
ElementType.PARAMETER(参数声明)
ElementType.CONSTRUCTOR(构造方法声明)
ElementType.LOCAL VARIABLE(局部变量声明)
ElementType.ANNOTATION_TYPE(注解)
ElementType.PACKAGE(包声明)
ElementType.TYPE_PARAMETER(jdk1.8开始提供的类型参数)
ElementType.TYPE_USE(jdk1.8开始提供的类型)
@Inherited – 是否允许子类继承该注解,该注解只有在类上使用时才会有效,对方法,属性等其他无效。
自定义注解
自定义注解类编写的一些规则:
Annotation型定义为@interface, 所有的Annotation会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口。
参数成员只能用public或默认(default)这两个访问权修饰
参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String、Enum、Class、annotations等数据类型,以及这一些类型的数组
在使用注解的时候成员必须赋值
value是一个特殊的参数名,在其他参数有默认值时或没有其他参数时,注解仅为value赋值时,可省略value定义,直接赋值。比如:
@RequestMapping("/test")
要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation对象,因为你除此之外没有别的获取注解对象的方法
注解也可以没有定义成员, 不过这样注解就没啥用了
自定义注解实例
定义类级别的TypeAnnotationTest
import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface TypeAnnotationTest { String value(); }
该注解使用的时候,在“运行时”有效,只能定义在“类”上,可以“被子类继承”,能“生成javadoc”,使用的时候可以省略value定义
定义方法级别的MethodAnnotationTest
import java.lang.annotation.*; @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MethodAnnotationTest { String testValue() default "" ; }
该注解使用的时候,在“运行时”有效,只能定义在“方法”上,能“生成javadoc”,使用的时候必须加上testValue定义
定义一个父类
@TypeAnnotationTest("parent annotation") public class Parent { @MethodAnnotationTest(testValue="parent sayHello method") public void sayHello(){ System.out.println("hello"); } }
这里TypeAnnotationTest使用的时候就省略了value定义,注意这里sayHello方法是public的
定义一个子类
public class Child extends Parent { @MethodAnnotationTest(testValue="child sayHello method") private String childSayHello(String msg){ return "child say:" +msg; } }
注意这里sayHello方法是private的
编写Test类
import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class Test { public static void main(String[] args) { try { Class clazz = Class.forName("Child"); // 找到类上面的注解 boolean isExist = clazz.isAnnotationPresent(TypeAnnotationTest.class); if (isExist) { TypeAnnotationTest typeAnnotation = (TypeAnnotationTest) clazz.getAnnotation(TypeAnnotationTest.class); System.out.println(typeAnnotation.value()); } // getDeclaredMethods能拿到所有(不包括继承的方法),而getMethods只能拿到public方法(包括继承的类或接口的方法) Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { Annotation[] annotations = method.getAnnotations(); for (Annotation annotation : annotations) { if (annotation instanceof MethodAnnotationTest) { System.out.println(((MethodAnnotationTest) annotation).testValue()); } } } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
结果输出
parent annotation child sayHello method
parent annotation parent sayHello method