注解
内置注解
@Override
@Deprecated
@SuppressWarning
元注解
元注解的作用是:注解其他注解。Java 中定义了四个元注解类型,用来对其他注解类型做说明。
描述注解的使用范围,是用于类、方法还是属性等。
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 {
}
|
说明该注解将被包含在 javadoc 中
说明子类可以继承父类中的该注解
自定义注解
使用 @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();
// ... ...
}
}
|