一 . Java 的反射原理
二 .得到Class类实例对象的三种方式
1.根据原理图可以看出,要想通过反射得到某个类中的所有内容,就得要先得到这个类对应的Class类实例对象
2. 三种方式: ① ____(类名).class; ② __(对象名).getClass(); ③ Class.forName(“类的路径”)
3. 示例: 首先先写一个Person类,作为之后要得到内容的类
package com.lzw.reforce;
public class Person {
// 属性
private String name;
private int id;
// 无参的构造方法
public Person() {}
// 有参数的构造方法
public Person(String name,int id) {
this.name=name;
this.id=id;
}
// 普通方法
public String getName() {return name;}
public int getId() {return id;}
public void setName(String name) {
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public String toString() {
return name+" "+id;
}
public static void print(String s) {
System.out.println(s);
}
}`
三种不同的得到Class实例对象的方式:
// 得到Class类对象的三种方式
// 1. __(类名).class;
// Class<Person> c2 = Person.class;
// 2. ___(对象名).getClass();
// Class c3 = new Person().getClass();
// 3. Class.forName(包括包名的类路径)
Class c = Class.forName("com.lzw.reforce.Person");
△ 注意:第三种方式中类路径是包括包名的(可以利用双击类名 — 右键 ---- Copy Qualified Name 快速得到)
- 很明显,在类中存在三部分内容,属性,构造方法以及其他的普通方法,分别对应了三个类。 属性 ----- Field 类 , 构造方法 ---- Constructor类 , 普通方法 ----- Method类
三.通过反射操作构造方法创建实例对象
1. 通过无参数的构造方法创建实例对象
Person p = (Person)c.newInstance(); // 直接通过Class类的newInstance方法创建实例对象
p.setName("小明");
p.setId(13);
System.out.println(p.getName()+" "+p.getId()); // 小明 13
2.通过有参数的构造方法创建实例对象
- 通过Class类的getConstructor方法得到该构造方法的对象
- 该方法传递的参数是要得到的构造方法的参数类型,以class形式传递
- 之后通过Constructor类的newInstance方法创建实例对象,参数就是构方的参数
Constructor con = c.getConstructor(String.class,int.class);
Person p2 = (Person)con.newInstance("小红",15);
System.out.println(p2.getName()+" "+p2.getId()); // 小红 15
四. 通过反射操作属性
- 通过Class类的getDeclaredField可得到该属性对应的Field类对象,参数为属性名
- Field 类对象有两个常用方法:get(Object obj) 和 set(Object obj, Object value)
- get方法的参数是要调用该属性的所属实例对象
- set方法的第一个参数是要设置属性的实例对象,第二个参数是设置的属性值
- setAccessible()方法设置是否允许设置或修改私有属性的值,默认是不允许
Field name = c.getDeclaredField("name"); // 获得name属性对应的Field类对象
Field id = c.getDeclaredField("id"); // 获得id属性对应的Field类对象
name.setAccessible(true); // 使反射可以操作私有属性
name.set(p2, "小江");
id.setAccessible(true);
id.set(p2, 10);
System.out.println(name.get(p2)+" "+id.get(p2)); // 小江 10
System.out.println(p2.getName()+" "+p2.getId()); // 小江 10
五.通过反射操作普通方法(若方法是私有方法,也要先调用setAccessible方法进行设置)
1. 调用非静态无参数的普通方法
- 通过Class类的getDeclaredMethod方法得到该普通方法对应的Method类对象,参数是方法名
- 通过Method类的invoke方法调用该方法,参数是调用该方法的实例对象
Method m = c.getDeclaredMethod("toString");
System.out.println(m.invoke(p)); // 小明 13
System.out.println(m.invoke(p2)); // 小江 10
2.调用非静态的有参数的普通方法
- 通过Class类的getDeclaredMethod方法得到该普通方法对应的Method类对象,第一个参数是该方法的名称,第二个参数是该方法中的参数类型,以class形式传递
- 通过Method类的invoke方法调用该方法,第一个参数是调用该方法的实例对象,第二个参数是该方法所需传的参数
Method set_name = c.getDeclaredMethod("setName",String.class);
set_name.invoke(p,"李华");
System.out.println(p.getName()); // 李华
3.调用静态方法
- 非静态方法的调用是 : 实例对象 . 方法名(参数),而静态方法的调用是 类名 . 方法名(参数),所以静态方法的调用不需要用到实例对象,所以在invoke方法中本应该传实例对象的参数改为null即可。
Method print = c.getDeclaredMethod("print",String.class);
print.invoke(null,"hello world"); // hello world