注解与反射

注解

内置注解

  • @Override

  • @Deprecated

  • @SuppressWarning

元注解

元注解的作用是:注解其他注解。Java 中定义了四个元注解类型,用来对其他注解类型做说明。

  • @Target

描述注解的使用范围,是用于类、方法还是属性等。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 该注解的作用范围为
// TYPE  描述类、接口(包括注解类型) 或enum声明
// FIELD  描述域即类成员变量
// METHOD  描述方法
// PARAMETER  描述参数
// CONSTRUCTOR  描述构造器
// LOCAL_VARIABLE  描述局部变量
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarning {
    String[] value();
}
  • @Retention
    • SOURCE 源文件中有效
    • CLASS class文件中有效
    • RUNTIME 运行时有效

注解的生命周期,在什么级别保留注解。

1
2
3
4
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)  // 源文件中有效
public @interface Override {
}
  • @Documented

说明该注解将被包含在 javadoc 中

  • @Inherited

说明子类可以继承父类中的该注解

自定义注解

使用 @interface 自定义注解,会默认继承 java.lang.annotation.Annotation 接口。

  • 只有一个参数,一般用 value 作为参数名。

  • 可以用 default 声明默认值。

    • String value() default "";

反射

反射机制允许程序在执行期间,使用反射 API 获取类的信息,并操作任意对象的内部属性及方法。

类加载后,在方法区中会产生一个 java.lang.Class 类型的对象,包含了类的信息。反射通过这个类,可以获取类的结构与信息。

在 JVM 中,每个类只存在一个 Class 对象,无论使用什么方式获取,都是一样的。(加载器每个类只会加载一次)

1
2
3
4
5
Class c = Class.forName("cn.letout.Person");

Class c = person.getClass();

Class c = Person.class;

获取类的信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Class<?> clazz = Class.forName("cn.letout.Test");

// 类的信息
clazz.getName();  // 包名 + 类名
clazz.getSimpleName();  // 类名

// 类的属性
Field[] publicFields = clazz.getFields();  // 获取 public 属性
Field[] fields = clazz.getDeclaredFields();  // 获取所有属性

Field nameField = clazz.getField("name");  // 获得指定属性

String name = nameField.getName();  // 获得属性名
Class<?> type = nameField.getType();  // 获得属性类型


// 类的方法
Method[] publicMethods = clazz.getMethods();
Method[] methods = clazz.getDeclaredMethods();

Method getNameMethod = clazz.getMethod("getName");  // 获得指定方法
Method setNameMethod = clazz.getMethod("setName", String.class);

String name = setNameMethod.getName();  // 获取方法名
Class<?> type = setNameMethod.getReturnType();  // 获取方法返回类型


// 类的构造器
Constructor[] publicConstructors = clazz.getConstructors();
Constructor[] constructors = clazz.getDeclaredConstructors();


// 类的注解
Annotation[] annotations = clazz.getAnnotations();

Annotation testAnnotation = clazz.getAnnotation(TestAnnotation.class);
String value = testAnnotation.value();

创建类的对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Class<Person> clazz = Person.class;

Person person = clazz.getConstructor().newInstance();
Person person = clazz.getConstructor(String.class).newInstance("name");

// 获取私有构造方法
// 使用 getDeclaredConstructor() 获取非 public 构造方法
Constructor<Person> constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Person person = constructor.newInstance("name");

调用类的方法

使用反射机制,调用类的方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Class clazz = Class.forName("cn.letout.Person");
Object instance = clazz.newInstance();

// 获取 public 方法
Method method = clazz.getMethod("test", String.class);
method.invoke(instance, "参数");

// 获取非 public 方法
Method privateMethod = clazz.getDeclaredMethod("fun", String.class);
privateMethod.setAccessible(true);
privateMethod.invoke(instance, "参数");

修改类的属性

1
2
3
4
5
6
Class clazz = Class.forName("cn.letout.Person");
Object instance = clazz.newInstance();

Field filed = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(instance, "Emery");

反射可以修改 final 修饰的常量属性。 如果 JVM 没有进行内联优化,可直接获取对应的值。如果 JVM 对其进行了内联优化,编译阶段已经将其替换成了常量的值,原代码可能输出原值。

1
2
3
4
// final name
System.out.println(person.name);
// 内联优化
System.out.println("Emery");

反射获取注解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 获取类注解
Annotation[] annotations = clazz.getAnnotations();
Annotation<Test> testAnnotation = clazz.getAnnotation(Test.class);

// 获取属性注解
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
    Annotation<Test> testAnnotation = field.getAnnotation(Test.class);
    if (testAnnotation ! = null) {
        String value = testAnnotation.value();
        // ... ...
    }
}
Licensed under CC BY-NC-SA 4.0