Java之注解.png
Java 注解用于为 Java 代码提供元数据。作为元数据,注解并不会直接影响你的代码执行。
1. 注解的定义
注解的定义与类的定义有些类似,只是将class换成@interfacexiu即可
public @interface AnnoTest {
}
但仅仅被
@interface
修饰还不够,一个完整的自定义注解还需要配合元注解使用。所以还先需要了解元注解是什么?怎么使用?
2. 注解分类
- JDK自带注解:@Override、@Deprecated、@SuppressWarning
- 元注解:@Target、@Retention、@Inherited、@Documented
- 自定义注解
2.1 JDK自带注解
-
@Override
:表示为被重写的方法 -
@Deprecated
:表示过时的方法 -
@SuppressWarning
:表示忽略警告
2.2 元注解
用来标记注解的注解
@Target
表示注解的作用域,通过枚举类
ElementType
表达作用类型,可以是类,方法,方法参数变量等。
其中枚举类ElementType
的取值如下:
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE, // 作用于接口、类、枚举、注解
/** Field declaration (includes enum constants) */
FIELD, // 作用于字段、枚举的常量
/** Method declaration */
METHOD, // 作用于方法
/** Formal parameter declaration */
PARAMETER, // 作用于方法参数
/** Constructor declaration */
CONSTRUCTOR, // 作用于构造方法
/** Local variable declaration */
LOCAL_VARIABLE, // 作用于局部变量
/** Annotation type declaration */
ANNOTATION_TYPE, // 作用于注解(@Retention注解中就使用该属性)
/** Package declaration */
PACKAGE, // 作用于包
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER, // 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
@Retention
表示注解存在的生命周期。注解存在阶段是保留在源码(编译期),字节码(类加载)或者运行期(JVM中运行)。通过枚举类
RetentionPolicy
来表示注解保留时期。
其中枚举类RetentionPolicy
的取值如下:
public enum RetentionPolicy {
/**
* 注解只存在源码中,编译时会丢弃
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* 注解会在class字节码文件中存在,在运行时可以通过反射获取到
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
@Documented
它的作用是能够将注解中的元素包含到 Javadoc 中去。
@Inherited
一个被
@Inherited
注解了的注解修饰了一个父类,如果他的子类没有被其他注解修饰,则它的子类也继承了父类的注解。
2.3 自定义注解(后面讲解)
3. 注解的作用
- 标记,用于告诉编译器的一些信息
- 编译时动态处理,如动态生成代码
- 运行时动态处理,如得到注解信息
4. 自定义注解并解析注解
4.1 自定义注解
- 使用@interface关键字定义注解
- 成员以无参无异常的方式声明
- 可以用default为成员指定默认值
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AnnoTest { // 使用@interface关键字定义注解
//成员以无参无异常的方式声明
String desc();
String author();
//可以用default为成员指定默认值
int age() default 18;
}
4.2 注解的属性类型
- 基本数据类型
- String类型
- 枚举类型
- 注解类型
- Class类型
- 以上类型的数组类型
4.3 使用注解
注解属性赋值:如果注解有多个属性,则可以在注解括号中用“,”号隔开分别给对应的属性赋值
@AnnoTest(desc="annotation class desc", author="annotation class author",age=20)
public class AnnoTestDemo {
@AnnoTest(desc="annotation method desc", author="annotation method author",age=30)
public String test() {
return "test";
}
}
4.4 解析注解
注:如果我们在定义自己的注解的时候,将@Retention(RetentionPolicy.RUNTIME)改为@Retention(RetentionPolicy.SOURCE)或者@Retention(RetentionPolicy.CLASS),运行上面的程序是不会出现任何结果,因为只有运行时注解可以通过反射获取,其他两种注解在运行时已经被丢弃了。
public static void main(String[] args) {
try {
//1、使用类加载器加载类
Class<?> c = Class.forName("com.anno.AnnoTestDemo");
//2、找到类上面的注解
//先判断AnnTestDemo类上面有没有AnnoTest这样的注解
boolean isExist = c.isAnnotationPresent(AnnoTest.class);
if (isExist) {
//3、获取类上的注解实例
AnnoTest classAnno = (AnnoTest) c.getAnnotation(AnnoTest.class);
System.out.println(classAnno.author());
}
//4、找到方法上的注解
//拿到给定类所包含的方法
Method[] methods = c.getDeclaredMethods();
//遍历方法
for (Method method : methods) {
boolean isMExist = method.isAnnotationPresent(AnnoTest.class);
if (isMExist) {
//拿到每个方法上的注解
AnnoTest methodAnno = method.getAnnotation(AnnoTest.class);
System.out.println(methodAnno.author());
}
}
//另外一种解析方法上注解的方式
//遍历所有的方法
for (Method method : methods) {
//拿到每个方法上的注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof AnnoTest) {
AnnoTest methodAnno = (AnnoTest) annotation;
System.out.println(methodAnno.author());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}