Java反射的概述
什么是Java的反射機(jī)制
Java反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意方法和屬性;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱為Java語言的反射機(jī)制。
Java的反射機(jī)制的作用
Java反射機(jī)制的主要作用是用來編寫一些通用性比較高的代碼或者框架
反射常用對(duì)象的概述
- Class
Class類的實(shí)例表示正在運(yùn)行的Java應(yīng)用程序中的類與接口 - Constructor
關(guān)于類的單個(gè)構(gòu)造方法的信息以及對(duì)它的訪問權(quán)限 - Field
Field提供有關(guān)類或接口的單個(gè)字段的信息,以及對(duì)它動(dòng)態(tài)訪問權(quán)限 - Method
Method 提供關(guān)于類或接口上單獨(dú)某個(gè)方法的信息
示意圖如下:

如,上圖示例程序中的Person.java在經(jīng)過編譯后變?yōu)?class文件,由ClassLoader加載到JVM的內(nèi)存中。原本的類中對(duì)應(yīng)的構(gòu)造方法,字段,方法等都會(huì)變?yōu)橄鄳?yīng)的Constructor對(duì)象,F(xiàn)ield對(duì)象,Method對(duì)象等
反射的API
Class 類
Java中的java.lang.Class類用于表示一個(gè)類的字節(jié)碼(.class)文件
如何獲得一個(gè)class文件對(duì)應(yīng)的Class對(duì)象呢?有三種方法:
- 類名.class
- 對(duì)象.getClass()
這種方式需要獲得具體的對(duì)象,并使用父類的Object.getClass()方法獲取 - Class.forName("包名.類名")
forName方法用于加載類字節(jié)碼到內(nèi)存中,并封裝成一個(gè)Class對(duì)象
對(duì)于這三種獲取方式,可以看示例:
現(xiàn)有Person類:
package classTest;
public class Person {
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person(){
}
public Person(String name,String sex){
this.name = name;
this.sex = sex;
}
public void sayHello(){
System.out.println("hello !");
}
}
@Test
public void test1(){
// 1 類名.class
Class clazzPerson1 = Person.class;
// 2 對(duì)象.getClass()
Person p = new Person();
Class clazzPerson2 = p.getClass();
// 3 Class.forName()
try {
Class clazzPerson3 = Class.forName("classTest.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
Constructor 類
- Constructor類的實(shí)例對(duì)象代表類的一個(gè)構(gòu)造方法
- 得到某個(gè)類所有的構(gòu)造方法
Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
- 得到指定的構(gòu)造方法并調(diào)用
Constructor constructor = Class.forName("java.lang.String").getConstructor(String.class);
String str = (String)constructor.newInstance("abc");
- Class類的newInstance() 方法用來調(diào)用類的默認(rèn)構(gòu)造方法
String obj = (String)Class.forName("java.lang.String").newInstance();
測試用例如下:
@Test
public void test2() throws Exception {
// 獲得無參的構(gòu)造方法
Class clazz = Class.forName("classTest.Person");
Constructor constructor = clazz.getConstructor();
Person p = (Person)constructor.newInstance();
p.sayHello();
// 獲得有參的構(gòu)造方法
Constructor constructor2 = clazz.getConstructor(String.class,String.class);
Person p2 = (Person)constructor2.newInstance("張三","男");
p2.sayHello();
System.out.println(p2.getName());
System.out.println(p2.getSex());
}
運(yùn)行結(jié)果如下:

Field 類
- Field類代表某個(gè)類中的一個(gè)成員變量,并提供動(dòng)態(tài)的訪問權(quán)限
- Filed對(duì)象的獲取
- 得到所有的成員變量
Field[] fields = clazz.getFields(); // 獲取所有public屬性 Field[] fields = clazz.getDeclaredFields(); // 取得所有聲明的屬性- 得到指定的成員變量
Field name = clazz.getField("name"); Field name = clazz.getDeclaredField("name"); - 設(shè)置Field變量是否可以訪問
field.setAccessible(boolean);
- Field變量值的讀取,設(shè)置
field.get(obj);
field.set(obj,value);
測試用例:
首先將Person類的name屬性變?yōu)楣校?/p>
package classTest;
public class Person {
public String name;
private String sex;
public Person(){
}
public Person(String name,String sex){
this.name = name;
this.sex = sex;
}
public void sayHello(){
System.out.println("hello !");
}
}
我們可以用Field對(duì)象來操作獲取字段,獲取字段值并設(shè)置字段值:
@Test
public void test3() throws Exception {
// 測試公有屬性
Class clazz = Class.forName("classTest.Person");
Person person = (Person) clazz.getConstructor().newInstance();
Field fieldName = clazz.getField("name");
fieldName.set(person,"李四");
System.out.println(fieldName.get(person));
// 測試私有屬性
Person person2 = (Person) clazz.getConstructor().newInstance();
Field fieldSex = clazz.getDeclaredField("sex");
fieldSex.setAccessible(true);
fieldSex.set(person2,"女");
System.out.println(fieldSex.get(person2));
}
顯示結(jié)果為:

Method 類
- Method 類代表某個(gè)類中的一個(gè)成員方法
- Method 對(duì)象的獲得
- 獲得所有方法
getDeclaredMethods() getMethods()- 獲得指定的方法
//name為方法名稱 getDeclredMethods(String name,Class<?>...parameterTypes) getMethods(String name,Class<?>...parameterTypes) - 通過反射執(zhí)行方法
invoke(Object obj,Object...args)
測試程序:
首先對(duì)Person類改動(dòng)如下:
package classTest;
public class Person {
public String name;
private String sex;
public Person(){
}
public Person(String name,String sex){
this.name = name;
this.sex = sex;
}
public void sayHello(){
System.out.println("hello !");
}
// 私有方法
private void run(){
System.out.println("run !");
}
// 私有帶參方法
private void eat(String foodName){
System.out.println("eat " + foodName + " !");
}
}
Method類可以對(duì)象可以獲取并操作屬于一個(gè)類的所有方法
@Test
public void test4() throws Exception {
// 測試共有方法
Class clazz = Class.forName("classTest.Person");
Person person = (Person) clazz.getConstructor().newInstance();
Method method = clazz.getMethod("sayHello");
method.invoke(person);
// 測試私有方法
Method method2 = clazz.getDeclaredMethod("run");
method2.setAccessible(true);
method2.invoke(person);
// 測試私有帶參的方法
Method method3 = clazz.getDeclaredMethod("eat", String.class);
method3.setAccessible(true);
method3.invoke(person,"apple");
}