注解基础
注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解。它主要的作用有以下四方面:
- 生成文档,通过代码里标识的元数据生成javadoc文档。
- 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。
- 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
- 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。
注意:注解是不支持继承
JAVA自带注解
包括@Override、@Deprecated和@SuppressWarnings:
@Override:表示当前的方法定义将覆盖父类中的方法@Deprecated:表示代码被弃用,如果使用了被@Deprecated注解的代码则编译器将发出警告@SuppressWarnings:表示关闭编译器警告信息
元注解
在JDK 1.5中提供了4个标准的元注解:@Target,@Retention,@Documented,@Inherited, 在JDK 1.8中提供了两个元注解 @Repeatable和@Native
Target
Target注解用来说明那些被它所注解的注解类可修饰的对象范围:注解可以用于修饰 packages、types(类、接口、枚举、注解类)、类成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数),在定义注解类时使用了@Target 能够更加清晰的知道它能够被用来修饰哪些对象,它的取值范围定义在ElementType 枚举中。
public enum ElementType {
TYPE,// 类、接口、枚举类
FIELD,// 成员变量(包括:枚举常量)
METHOD,// 成员方法
PARAMETER,// 方法参数
CONSTRUCTOR,// 构造方法
LOCAL_VARIABLE,// 局部变量
ANNOTATION_TYPE,// 注解类
PACKAGE,// 可用于修饰:包
TYPE_PARAMETER,// 类型参数,JDK 1.8 新增
TYPE_USE;// 使用类型的任何地方,JDK 1.8 新增
private ElementType() {
}
}
Reteniton
Reteniton注解用来限定那些被它所注解的注解类在注解到其他类上以后,可被保留到何时,一共有三种策略,定义在RetentionPolicy枚举中。
public enum RetentionPolicy {
SOURCE, // 源文件保留
CLASS, // 编译期保留,默认值
RUNTIME // 运行期保留,可通过反射去获取注解信息
}
Documented
Documented注解的作用是:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息。
Inherited
Inherited注解的作用:被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
Repeatable
重复注解:在java1.8添加,允许在同一申明类型(类,属性,或方法)的多次使用同一个注解。 java 8之前也有重复使用注解的解决方案,但可读性不是很好。事例代码:
//JAVA 1.5实现重复注解
public @interface Authority {
String role();
}
public @interface Authorities {
Authority[] value();
}
public class Test {
@Authorities({@Authority(role="Admin"),@Authority(role="Manager")})
public void doSome(){
}
}
//JAVA 8 实现重复注解
@Repeatable(Authorities.class)
public @interface Authority {
String role();
}
public @interface Authorities {
Authority[] value();
}
public class Test {
@Authority(role="Admin")
@Authority(role="Manager")
public void doSome(){ }
}
Native
使用 @Native 注解修饰成员变量,则表示这个变量可以被本地代码引用,常常被代码生成工具使用。对于 @Native 注解不常使用,了解即可
注解与反射接口
在自定义注解中,@Reteniton 使用RUNTIME类型。可以通过反射包java.lang.reflect下的AnnotatedElement接口提供这些方法。获取注解内容。
AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的方法来访问Annotation信息。
boolean isAnnotationPresent(Class<?extends Annotation> annotationClass)
判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false。注意:此方法会忽略注解对应的注解容器。
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
Annotation[] getAnnotations()
返回该程序元素上存在的所有注解,若没有注解,返回长度为0的数组。
<T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
返回该程序元素上存在的、指定类型的注解数组。没有注解对应类型的注解时,返回长度为0的数组。该方法的调用者可以随意修改返回的数组,而不会对其他调用者返回的数组产生任何影响。getAnnotationsByType方法与 getAnnotation的区别在于,getAnnotationsByType会检测注解对应的重复注解容器。若程序元素为类,当前类上找不到注解,且该注解为可继承的,则会去父类上检测对应的注解。
<T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
返回直接存在于此元素上的所有注解。与此接口中的其他方法不同,该方法将忽略继承的注释。如果没有注释直接存在于此元素上,则返回null
<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
返回直接存在于此元素上的所有注解。与此接口中的其他方法不同,该方法将忽略继承的注释
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注解及注解对应的重复注解容器。与此接口中的其他方法不同,该方法将忽略继承的注解。如果没有注释直接存在于此元素上,则返回长度为零的一个数组。该方法的调用者可以随意修改返回的数组,而不会对其他调用者返回的数组产生任何影响。
自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestMethodAnnotation {
public String name() default "";
public String value() default "";
}
public class Test{
@TestMethodAnnotation(name="11",value="22")
public void test1(){
}
}
public class Main{
public static void main(String[] args){
Method[] methods= Test.class.getMethods()
for (Method method : methods) {
// 方法上是否有TestMethodAnnotation注解
if (method.isAnnotationPresent(TestMethodAnnotation.class)) {
try {
// 获取并遍历方法上的所有注解
for (Annotation anno : method.getDeclaredAnnotations()) {
System.out.println("Annotation in Method '"
+ method + "' : " + anno);
}
// 获取MyMethodAnnotation对象信息
TestMethodAnnotation methodAnno = method
.getAnnotation(TestMethodAnnotation.class);
System.out.println(methodAnno.name());
} catch (Throwable ex) {
ex.printStackTrace();
}
}
}
}
}