注解
内置注解
- @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();
        // ... ...
    }
}
 |