注解简介:
注解的主要作用有以下四方面:
-
生成文档
-
编译检查
-
编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
-
运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。
注解的分类:
内置注解
-
@Override
,用于标明方法重写 -
@Deprecated
,用于标明弃用的类或方法,如果使用了被@Deprecated
注解的代码则编译器将发出警告 -
@SuppressWarnings
,标明忽略警告,如@SuppressWarnings("rawtypes")
(具体忽略警告类型略)
元注解
元注解是用于定义注解的注解,包括@Target
、@Retention
、@Documented
、@Inherited
(JDK1.5)和@Repeatable
和@Native
(JDK1.8):
-
@Target
,用于标明注解使用的范围 -
@Retention
,用于标明注解被保留的时间 -
@Documented
,用于标明该注解会生成javadoc文档 -
@Inherited
,用于标明注解会被继承 -
@Repeatable
,重复注解 -
@Vative
,用于标明成员变量可以被本地代码引用(通常适用于代码生成工具,以下不做详解)
自定义注解
可以根据自己的需求定义注解,并可用元注解对自定义注解进行注解。
元注解:
@Target
@Target
注解,用于标明注解使用的范围
public enum ElementType {
TYPE, //类、接口、枚举类
FIELD, //成员变量(包括:枚举常量)
METHOD, //成员方法
PARAMETER, //方法参数
CONSTRUCTOR, //构造方法
LOCAL_VARIABLE, //局部变量
ANNOTATION_TYPE, //注解类
PACKAGE, //可用于修饰:包
TYPE_PARAMETER, //类型参数,JDK 1.8 新增
TYPE_USE //使用类型的任何地方,JDK 1.8 新增
}
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
使用方法:
@Target(ElementType.METHOD) //单参数
@Target(value={TYPE, FIELD, METHOD}) //多参数
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention
@Retention
,用于标明注解被保留的时间
public enum RetentionPolicy {
SOURCE, //源文件保留,(只在源码中保留)
CLASS, //编译期保留,默认值
RUNTIME //运行期保留,可通过反射去获取注解信息
}
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
使用方法:
@Retention(RetentionPolicy.CLASS)
@Documented
@Documented
,用于标明该注解会生成javadoc文档
使用方法:
@Documented
@Inherited
@Inherited
,用于标明注解会被继承
使用方法:
@Inherited
@Repeatable
@Repeatable
,重复注解,即允许在同一申明类型中(类,属性,或方法)多次使用同一个注解
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
Class<? extends Annotation> value();
}
使用方法与样例:
@Repeatable(Authorities.class)
public @interface Authority {
String role();
}
public @interface Authorities {
Authority[] value();
}
public class RepeatAnnotationUseNewVersion {
@Authority(role="Admin")
@Authority(role="Manager")
public void doSomeThing(){ }
}
注解与反射接口:
-
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()
返回直接存在于此元素上的所有注解及注解对应的重复注解容器。
自定义接口:
定义接口
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface myAnnotation{
public String name() default ""; //default 缺省为""
public String content();
}
使用接口
@myAnnotation(name = "name",content = "lty")
public String userAnnotation() {
return "userAnnotation";
}
使用反射获取接口(接口测试)
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class Main {
@myAnnotation(name = "name",content = "lty")
public String userAnnotation() {
return "userAnnotation";
}
public static void main(String[] args) {
try {
// 获取所有methods
Method[] methods = Main.class.getClassLoader()
.loadClass(("Main")).getMethods();
// 遍历
for (Method method : methods) {
// 方法上是否有myAnnotation注解
if (method.isAnnotationPresent(myAnnotation.class)) {
try {
// 获取并遍历方法上的所有注解
for (Annotation anno : method.getDeclaredAnnotations()) {
System.out.println("Annotation in Method '"
+ method + "' : " + anno);
}
// 获取myAnnotation对象信息
myAnnotation methodAnno = method
.getAnnotation(myAnnotation.class);
System.out.println(methodAnno.name());
} catch (Throwable ex) {
ex.printStackTrace();
}
}
}
} catch (SecurityException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}