一、概念
Java 反射(Reflection)就是 Java 程序在运行时可以加载一个才知道类名的类,获得类的完整构造方法,并实例化出对象,给对象属性设定值或者调用对象的方法。这种在运行时动态获取类的信息以及动态调用对象的方法的功能称为 Java 的反射机制。
二、Class 类
Class 类继承自 Object 类,是 Java 反射机制的入口,封装了一个类或接口的运行时信息,通过调用 Class 类的方法可以获取到这些信息。怎么理解这个 Class 类呢?如果说普通类是所有对象方法、属性的集合,那就可以把这个 Class 类理解成是所有普通类的集合。
下面列举了获取 Class 类的几种方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class TestClass {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> aClass0 = Class.forName( "java.lang.Object" );
Class<Integer> aClass1 = Integer.class;
Class<Integer> aClass2 = Integer.TYPE;
String str = "Hello, World" ;
Class<? extends String> aClass3 = str.getClass();
Class<?> aClass4 = aClass3.getSuperclass();
System.out.println(aClass0.getName());
System.out.println(aClass1.getName());
System.out.println(aClass2.getName());
System.out.println(aClass3.getName());
System.out.println(aClass4.getName());
}
}
|
三、获取类信息
为了测试 Java 的反射机制,我新建了一对父子类,其中涵盖了四种封装属性,以尽可能的测试多种类信息的获取:
Vehicle.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
vpublic class Vehicle {
private String color;
protected Integer seat;
int year;
public Date createdOn;
private String getColor() {
return color;
}
protected Integer getSeat() {
return seat;
}
int getYear() {
return year;
}
public Date getCreatedOn() {
return createdOn;
}
}
|
Car.java
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
|
public class Car extends Vehicle {
private String brand;
protected Integer a;
int b;
public Date updatedOn;
public Car(){}
private Car(String brand, Integer a, int b, Date updatedOn) {
this .brand = brand;
this .a = a;
this .b = b;
this .updatedOn = updatedOn;
}
private String getBrand() {
return brand;
}
protected Integer getA() {
return a;
}
int getB() {
return b;
}
public Date getUpdatedOn() {
return updatedOn;
}
}
|
1、获取方法
Class 类对方法的获取主要通过以下两种方式:
Method[] getMethods() 返回该类或接口的所有可访问公共方法(含继承的公共方法)。
Method[] getDeclaredMethods() 返回该类或接口的所有方法(不含继承的方法)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class TestMethod {
public static void main(String[] args) {
Class<Car> carClass = Car.class;
Method[] methods = carClass.getMethods();
Method[] declaredMethods = carClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println( "方法名:" + method.getName());
System.out.println( "该方法所在的类或接口:" + method.getDeclaringClass());
System.out.println( "该方法的参数列表:" + method.getParameterTypes());
System.out.println( "该方法的异常列表:" + method.getExceptionTypes());
System.out.println( "该方法的返回值类型:" + method.getReturnType());
}
}
}
|
2、获取属性
Class 类对属性的获取主要通过以下两种方式:
Field[] getFields() :存放该类或接口的所有可访问公共属性(含继承的公共属性)。
Field[] getDeclaredFields():存放该类或接口的所有属性(不含继承的属性)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class TestField {
public static void main(String[] args) {
Class<Car> carClass = Car.class;
Field[] fields = carClass.getFields();
Field[] declaredFields = carClass.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println( "属性名称是:" + field.getName());
System.out.println( "该属性所在的类或接口是:" + field.getDeclaringClass());
System.out.println( "该属性的类型是:" + field.getType());
System.out.println( "该属性的修饰符是:" + Modifier.toString(field.getModifiers()));
}
}
}
|
3、获取构造函数
Class 类对构造方法的获取主要通过以下两种方式:
Constructor<?>[] getConstructors() :返回该类或接口的所有的公共构造方法
Constructor<?>[] getDeclaredConstructors():返回该类或接口的所有构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class TestConstructor {
public static void main(String[] args) throws NoSuchMethodException {
Class<Car> carClass = Car.class;
Constructor<?>[] constructors = carClass.getConstructors();
Constructor<?>[] declaredConstructors = carClass.getDeclaredConstructors();
Constructor<Car> carConstructor = carClass.getDeclaredConstructor(String.class, Integer.class, Integer.TYPE, Date.class);
for (Constructor constructor : constructors) {
System.out.println( "该构造器的名称是:" + constructor.getName());
System.out.println( "该构造器所在的类或接口是:" + constructor.getDeclaringClass());
constructor.getParameterTypes();
}
}
}
|
四、动态调用
到目前为止,我们都是通过 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
|
public class Test {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class<Car> carClass = Car.class;
Car car = carClass.newInstance();
Constructor<Car> declaredConstructor = carClass.getDeclaredConstructor(String.class, Integer.class, Integer.TYPE, Date.class);
declaredConstructor.setAccessible( true );
Car car1 = declaredConstructor.newInstance( "brand" , 21, 21, new Date());
System.out.println(car1.getUpdatedOn());
Field brand = carClass.getDeclaredField( "brand" );
brand.setAccessible( true );
System.out.println( "取消访问权限控制后的值:" + brand.get(car1));
brand.set(car1, "dnarb" );
System.out.println( "修改属性后的值是:" + brand.get(car1));
Method getBrand = carClass.getDeclaredMethod( "getBrand" );
getBrand.setAccessible( true );
System.out.println( "调用反射方法得到的值是:" + getBrand.invoke(car1));
}
|