关于 Class 类、Method 类以及 Field 类的使用方式解析:
1. 要想使用反射,首先需要获得待处理类或对象所对应的 Class 对象。
2. 获取某个类或某个对象所对应的 Class 对象的常用 3 种方式:
a. 使用 Class 类的静态方法 forName();
// 参数为要获取的 Class 类的包名,eg: Class<?> classType = Class.forName("java.lang.String");
public static Class<?> forName(String className)
throws ClassNotFoundException {
...
}
b. 使用类的 .class 语法;
eg: String.calss
c. 使用对象的 geyClass() 方法;
eg:
String s = "ym";
Class<?> clazz = s.getClass();
3. 若想通过类的不带参数的构造方法来生成对象,我们有两种方式:
a. 先获取 Class 对象,然后通过该 Class 对象的 newInstance() 方法直接生成即可(已废弃):
Class<?> classType = String.class;
Object obj = classType.newInstance();
b. 先获取 Class 对象,然后通过该对象获得对应的 Constructor 对象,再通过该 Constructor 对象的 newInstance() 方法生成:
Class<?> classType = String.class;
Constructor cons = classType.getConstructor(new Class[]{});
Object obj = cons.newInstance(new Object[]{});
4. 若想通过类的带参构造方法来生成对象,只能通过 3 中的 b 方法。
eg1:通过反射实现一个对象的 copy,并返回和原对象属性一样的新对象。
public class ReflectionTest {
// 该方法实现对 Customer 对象的拷贝操作
public Object copy(Object object) throws Exception {
// 1. 获取 Customer 类的 Class 对象
// 方法 3 :
Class<?> classType = object.getClass();
// 2. 获取 Customer 对象的一个实例,这个就是最后返回的新对象
// 通过无参构造方法创建
Constructor cons = classType.getConstructor();
Object newObj = cons.newInstance();
// 通过有参构造方法创建
// Constructor cons = classType.getConstructor(new Class[]{String.class, int.class});
// Object newObj = cons.newInstance(new Object[]{"ym", 20});
// 3. 获取 Customer 对象的所有成员变量
Field[] fields = classType.getDeclaredFields();
for(Field field : fields){
// 获取 属性 的名称
String name = field.getName();
// 获取字符的首字母,并将其转换成大写
String firstLetter = name.substring(0, 1).toUpperCase();
// name.substring(1) 等价于 name.substring(1, name.length)
String getMethodName = "get" + firstLetter + name.substring(1);
String setMethodName = "set" + firstLetter + name.substring(1);
Method getMethod = classType.getMethod(getMethodName, new Class[]{});
Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()});
Object value = getMethod.invoke(object, new Object[]{});
setMethod.invoke(newObj, new Object[]{value});
}
return newObj;
}
public static void main(String[] args) throws Exception {
Customer customer = new Customer("ym", 18);
customer.setId(1L);
ReflectionTest reflectionTest = new ReflectionTest();
Customer newCustomer = (Customer) reflectionTest.copy(customer);
System.out.println(newCustomer.getId()+", " + newCustomer.getName() + ", " + newCustomer.getAge());
}
}
class Customer{
private Long id;
private String name;
private int age;
public Customer() {
}
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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;
}
}
// output
1, ym, 18
5. java.lang.Array 类提供了动态创建和访问数组元素的各种静态方法。
eg1: 先创建一个长度为 10 的字符串数组,接着把索引位置为 5 的元素设置为 “ym”,然后再读取该位置元素的值。
public class ArrayTest {
public static void main(String[] args) throws Exception{
Class<?> classType = Class.forName("java.lang.String");
// 生成一个数组对象
Object array = Array.newInstance(classType, 10);
Array.set(array, 5, "ym");
System.out.println(Array.get(array, 5));
}
}
// output
ym
6. Integer.TYPE 返回的是 int,而 Integer.class 返回的是 Integer 类所对应的 Class 对象。
public class ArrayTest {
public static void main(String[] args) throws Exception{
System.out.println(Integer.TYPE);
System.out.println(Integer.class);
}
}
// output
int
class java.lang.Integer
eg2: 对多维数组的操作
public class ArrayTest {
public static void main(String[] args) throws Exception{
int[] dims = new int[]{ 5, 10, 15 };
// 这里第二个参数类型是维度,也就是生成了一个 3 维数组。array[5][10][15]。
Object array = Array.newInstance(Integer.TYPE, dims);
// 获取 第一维 索引为 3 个数组,也就是 array[3][][],所以 arrayObj 其实就是一个二维数组。
Object arrayObj = Array.get(array, 3);
Class<?> classType = arrayObj.getClass().getComponentType();
arrayObj = Array.get(arrayObj, 5);
Array.setInt(arrayObj, 10, 37);
int[][][] arratCast = (int[][][]) array;
System.out.println(arratCast[3][5][10]);
}
}
// output
37
7. 通过反射调用外部类中的私有方法、访问对象的私有成员变量
eg1: 通过反射调用外部类私有方法
public class PrivateTest {
// 私有方法
private String testOne(String s){
return "ym: " + s;
}
}
// 通过反射调用 PrivateTest 的私有方法
public class Test {
public static void main(String[] args) throws Exception {
PrivateTest privateTest = new PrivateTest();
// 获取 PrivateTest 的 Class 对象
Class<?> classType = privateTest.getClass();
// 获取 Method 对象
Method method = classType.getDeclaredMethod("testOne", new Class[]{ String.class });
// 压制 Java 的访问控制检查
method.setAccessible(true);
String str = (String) method.invoke(privateTest, new Object[]{ "test" });
System.out.println(str);
}
}
// output
ym: test
eg2:通过反射修改外部类私有属性值
public class PrivateTest {
// 私有属性
private String name = "cfm";
public String getName() {
return name;
}
}
public class Test {
public static void main(String[] args) throws Exception {
PrivateTest privateTest = new PrivateTest();
// 获取 PrivateTest 的 Class 对象
Class<?> classType = privateTest.getClass();
// 获取 Field 对象
Field field = classType.getDeclaredField("name");
field.setAccessible(true);
field.set(privateTest, "ym");
System.out.println(privateTest.getName());
}
}
// output
ym