注解&反射注解
1. 注解的定义
public interface Annotation 是所有的注解的父接口
1.1 注解属性的类型
- 8种基本类型 byte short char int long float double boolean
- String
- Enum
- Class
- 注解类型
- 以上类型的一维数组类型
1.2 定义格式
public @interface MyAnno {
int age() default 22;
String name();
MyEnum myEnum();
Class clazz();
YourAnno anno();
String[] value();
}
定义注解时,可以给注解属性指定默认值,使用时可以不给带有默认值的属性赋值。
1.3 注解的使用
@MyAnno(
name = "XiaoMing",
myEnum = MyEnum.RED,
clazz = Object.class,
anno = @YourAnno,
value = "Hello")
public class AnnoTest {
}
- 当使用注解时,如果只给(只有value属性)名为value的属性赋值时,可以省略“value=”,例如: @MyAnno1(value=“hello”),可以书写成 @MyAnno1(“hello”)
- 当给数组类型的属性赋值时,若数组元素的个数为1时,可以省略大括号
所以有简写:
public @interface MyAnno {
String[] value();
}
@MyAnno("Hello")
public class AnnoTest {
}
2. 作用目标限定以及保存策略限定
2.1 作用目标限定
这代码中有这些位置可以使用注解
- 接口、类、枚举
- 注解
- 字段、枚举常量
- 方法
- 构造器
- 参数
- 局部变量
- 包
那我们如何限定只有某几个位置可以使用该注解呢?答案给注解添加 @Target 注解来限定作用目标
@Target源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value(); // 枚举数组
}
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,
/** Package declaration */
// 包
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
// 泛型参数声明
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
// 泛型类型
TYPE_USE
}
其中有两个是jdk1.8新加的属性
把自定义的注解限定在类或方法上
@Target(value = {ElementType.TYPE, ElementType.METHOD})
public @interface MyAnno {
int age() default 22;
String name();
MyEnum myEnum();
Class clazz();
YourAnno anno();
String[] value();
}
2.2 保存策略限定
- 源代码文件(SOURCE):注解只在源代码中存在,当编译时就被忽略了
- 字节码文件(CLASS):注解在源代码中存在,然后编译时会把注解信息放到了class文件,但JVM在加载类时,会忽略注解
- JVM中(RUNTIME):注解在源代码、字节码文件中存在,并且在JVM加载类时,会把注解加载到JVM内存中(它是唯一可反射注解!)
使用 @Retention 注解保留策略
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
RetentionPolicy
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* 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,
/**
* 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
}
给自定义注解加保留策略
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE, ElementType.METHOD})
public @interface MyAnno {
int age() default 22;
String name();
MyEnum myEnum();
Class clazz();
YourAnno anno();
String[] value();
}
这样就可以使用反射获取注解的值了,这也是很多框架注解常用的定义方式。
3. 注解反射
要想反射,注解的保留策略必须是 RUNTIME
3.1 作用目标上返回
- 类上的注解,需要使用Class来获取
- 方法上的注解,需要Method来获取
- 构造器上的注解,需要Construcator来获取
- 成员上的,需要使用Field来获取
- …
3.2 获取方法:
- Annotation getAnnotation(Class),返回目标上指定类型的注解
- Annotation[] getAnnotations(),返回目标上所有注解
public class AnnoTestTest {
@Test
public void testAnnoReflect() {
Class<AnnoTest> clazz = AnnoTest.class;
MyAnno myAnno = clazz.getAnnotation(MyAnno.class);
System.out.println("age: " + myAnno.age());
System.out.println("name: " + myAnno.name());
System.out.println("myEnum: " + myAnno.myEnum());
System.out.println("clazz: " + myAnno.clazz());
System.out.println("myAnno: " + myAnno.anno());
System.out.println("value: " + Arrays.toString(myAnno.value()));
System.out.println("--------------------------------------");
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof MyAnno) {
System.out.println("是自定义注解MyAnno");
}
}
}
}
测试结果:
age: 22
name: XiaoMing
myEnum: RED
clazz: class java.lang.Object
myAnno: @com.yp.anno.YourAnno()
value: [Hello]
--------------------------------------
是自定义注解MyAnno
本文详细介绍了Java中的注解,包括注解的定义、属性类型、定义格式和使用方法。接着讨论了注解的作用目标限定和保存策略,如@Target和@Retention的使用。最后,文章探讨了注解的反射机制,如何通过反射获取不同作用目标上的注解信息。
2175

被折叠的 条评论
为什么被折叠?



