Appearance
Java 反射
反射是指能通过类字节码对象剖析类结构,包括成员变量、构造方法和成员方法。

1. 获取Class对象
获取Class对象有三种方式:
Class.forName("全类名"):最常用的方式;类名.class:一般用于参数传递;对象.getClass():已经有某类对象时才可以使用;
下面的例子基于Student类来获取Class对象:
java
public static void main(String[] args) throws ClassNotFoundException {
// 方式一:Class.forName()
Class<?> clazz01 = Class.forName("com.lee.reflect.Student");
System.out.println(clazz01);
// 方式二:类名.class
Class<Student> clazz02 = Student.class;
System.out.println(clazz02);
// 方式三:对象.getClass()
Student student = new Student();
Class<? extends Student> clazz03 = student.getClass();
System.out.println(clazz03);
System.out.println(clazz01 == clazz02);
System.out.println(clazz02 == clazz03);
}java
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
protected Student(String name){
this.name = name;
}
private Student(int age){
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}可以看到,只要是同一个类,三种方式获取的Class对象是相同的。
2. 构造方法
2.1 获取构造方法对象
构造方法可以通过Constructor类来表示,在Class类中用于获取构造方法的方法如下:
Constructor<?>[] getConstructors():返回所有的公共构造方法对象;Constructor<?>[] getDeclaredConstructors():返回所有的构造方法对象;Constructor<T> getConstructor(Class<?>... parameterTypes):返回单个公共构造方法对象;Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回单个构造方法对象;
java
public static void main(String[] args) throws NoSuchMethodException {
Class<Student> clazz = Student.class;
System.out.println("====================");
for (Constructor<?> constructor : clazz.getConstructors()) {
System.out.println(constructor);
}
System.out.println("====================");
for (Constructor<?> declaredConstructor : clazz.getDeclaredConstructors()) {
System.out.println(declaredConstructor);
}
System.out.println("====================");
Constructor<Student> constructor = clazz.getConstructor(String.class, int.class);
System.out.println(constructor);
System.out.println("====================");
Constructor<Student> declaredConstructor = clazz.getDeclaredConstructor(int.class);
System.out.println(declaredConstructor);
}txt
====================
public com.lee.reflect.Student()
public com.lee.reflect.Student(java.lang.String,int)
====================
public com.lee.reflect.Student()
private com.lee.reflect.Student(int)
protected com.lee.reflect.Student(java.lang.String)
public com.lee.reflect.Student(java.lang.String,int)
====================
public com.lee.reflect.Student(java.lang.String,int)
====================
private com.lee.reflect.Student(int)2.2 通过构造方法对象创建类对象
我们可以通过以下方法创建对象:
T newInstance(Object ... initargs)
java
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<Student> clazz = Student.class;
Constructor<Student> declaredConstructor = clazz.getDeclaredConstructor(int.class);
// 设置可访问,即私有方法(构造方法)也是可以被调用的
declaredConstructor.setAccessible(true);
// 调用构造方法
Student s = declaredConstructor.newInstance(1);
System.out.println(s);
}txt
Student{name='null', age=1}3. 成员变量
3.1 获取成员变量
成员变量可以通过类Field表示,在Class类中有以下方法可以获取成员变量对象:
Field[] getFields():获取所有公共的成员变量对象;Field[] getDeclaredFields():获取所有成员变量对象;Field getFields(String name):获取单个公共成员变量对象;Field getDeclaredField(String name):获取单个成员变量对象;
3.2 使用成员变量对象
我们可以使用get(Object obj)来获取该成员变量在某个对象上的值:
java
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Class<Student> clazz = Student.class;
Student student = new Student("张三", 18);
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
// 获取某个对象上该成员变量的值
Object o = name.get(student);
System.out.println(o); // 张三
}也可以使用set(Object obj, Object value)修改某个对象中该成员变量的值:
java
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Class<Student> clazz = Student.class;
Student student = new Student("张三", 18);
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
// 修改某个对象上该成员变量的值
name.set(student, "李四");
System.out.println(student); // Student{name='李四', age=18}
}4. 成员方法
4.1 获取成员方法
我们可以使用Method来表示成员方法,在Class中有以下方法可以获取成员方法:
Method[] getMethods():获取所有公共成员方法,包括继承的;Method[] getDeclaredMethods():获取所有成员方法对象,不包括继承的;Method getMethod(String name, Class<?>... parameterTypes):获取单个公共的成员方法对象;Method getDeclaredMethod(String name, Class<?>... parameterTypes):获取单个成员方法对象;
4.2 调用成员方法
我们可以使用Method对象上的Object invoke(Object obj, Object... args)方法调用某个对象上的成员方法:
- 第一个方法参数表示要在哪个对象上调用方法;
- 第二个方法参数表示成员方法参数;
- 调用返回值表示成员方法的返回值;
java
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class<Student> clazz = Student.class;
// 获取成员方法
Method toString = clazz.getDeclaredMethod("toString");
toString.setAccessible(true);
// 调用成员方法
Object o = toString.invoke(new Student("张三", 18));
System.out.println(o);
}5. 其他方法
在Class类中,还有以下方法可以获取相关信息。
5.1 获取父类
Class<? super T> getSuperclass():获取父类;
java
public static void main(String[] args) {
Class<Student> clazz = Student.class;
Class<? super Student> superclass = clazz.getSuperclass();
System.out.println(superclass); // class java.lang.Object
}5.2 获取实现的接口
Class<?>[] getInterfaces():获取实现的接口,接口不包括泛型信息或注解信息;AnnotatedType[] getAnnotatedInterfaces():获取实现的接口的完整类型信息,包括泛型参数和注解信息。
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE) // 注意
public @interface MyAnnotation {
String value();
}java
interface A<T>{}
interface B{}
interface C{}
public class MyClass
implements @MyAnnotation("This is A") A<String> ,
B,
@MyAnnotation("This is C") C {
}java
public static void main(String[] args) throws ClassNotFoundException {
Class<?> clazz = Class.forName("com.lee.reflect.MyClass");
AnnotatedType[] annotatedInterfaces = clazz.getAnnotatedInterfaces();
for (AnnotatedType annotatedInterface : annotatedInterfaces) {
System.out.println("Interface: " + annotatedInterface.getType());
if (annotatedInterface.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = annotatedInterface.getAnnotation(MyAnnotation.class);
System.out.println("Annotation: " + annotation);
}
}
}txt
Interface: com.lee.reflect.A<java.lang.String>
Annotation: @com.lee.reflect.MyAnnotation(value=This is A)
Interface: interface com.lee.reflect.B
Interface: interface com.lee.reflect.C
Annotation: @com.lee.reflect.MyAnnotation(value=This is C)5.3 获取注解
注解可以用Annotation类来表示,在Class类中可以用以下方法获取注解对象:
Annotation[] getAnnotations():返回所有注解(包括继承的注解)。Annotation[] getDeclaredAnnotations():返回直接声明的注解(不包括继承的注解)。<A extends Annotation> A getAnnotation(Class<A> annotationClass):返回指定类型的注解(包括继承的注解)。<A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass):返回指定类型的注解(不包括继承的注解)。
例如:
java
// 定义一个可继承的注解
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface MyInheritedAnnotation {
String value();
}
// 定义一个不可继承的注解
@Retention(RetentionPolicy.RUNTIME)
@interface MyNonInheritedAnnotation {
String value();
}java
// 父类使用两个注解
@MyInheritedAnnotation("Inherited Annotation Value")
@MyNonInheritedAnnotation("Non-Inherited Annotation Value")
class ParentClass {
}
// 子类不显式使用任何注解
class ChildClass extends ParentClass {
}java
public static void main(String[] args) {
// 获取父类的注解
System.out.println("Parent Class Annotations:");
Annotation[] parentAnnotations = ParentClass.class.getAnnotations();
for (Annotation annotation : parentAnnotations) {
System.out.println(annotation.annotationType().getSimpleName());
}
// 获取子类的注解
System.out.println("\nChild Class Annotations:");
Annotation[] childAnnotations = ChildClass.class.getAnnotations();
for (Annotation annotation : childAnnotations) {
System.out.println(annotation.annotationType().getSimpleName());
}
}txt
Parent Class Annotations:
MyInheritedAnnotation
MyNonInheritedAnnotation
Child Class Annotations:
MyInheritedAnnotation如果要获取成员变量、方法、参数上的注解,可以分别使用Field、Method、Parameter(表示方法参数)类中的方法。