Java反射機制核心類Class、Constructor、Method、Field詳解

反射是 Java 中一種強大的動態(tài)編程機制,它允許程序在運行時獲取類的元數(shù)據(jù)(如類名、屬性、方法、構造器等),并動態(tài)操作類的成員(即使是私有成員)。這種特性讓 Java 具備了極高的靈活性,也是 Spring、MyBatis 等框架的核心底層技術。
本文將深入剖析反射機制的四大核心類:Class(類對象)、Constructor(構造方法)、Method(成員方法)、Field(成員屬性),結合實例和圖解,幫你徹底搞懂反射的工作原理。
一、反射的 “入口”:Class 類(類對象)
Class類是反射的基礎 —— 它是所有類的 “元數(shù)據(jù)容器”。每個類在 JVM 中都有且僅有一個對應的Class對象,通過這個對象可以獲取該類的所有信息(屬性、方法、構造器等)。
1. 什么是 Class 對象?
當一個類被加載到 JVM 時,JVM 會為其創(chuàng)建一個Class類型的對象(注意:Class本身也是一個類),這個對象包含了該類的完整結構信息。我們可以把Class對象理解為 “類的說明書”,通過它能知道這個類有哪些屬性、方法、構造器,以及類的繼承關系等。
2. 獲取 Class 對象的 3 種方式
獲取Class對象是反射操作的第一步,常用的有 3 種方式,適用場景不同:
| 方式 | 代碼示例 | 特點 |
|---|---|---|
對象調用getClass() | User user = new User(); Class<?> clazz = user.getClass(); | 需先創(chuàng)建對象,適合已有實例的場景 |
類名直接訪問.class | Class<?> clazz = User.class; | 無需創(chuàng)建對象,不會觸發(fā)類的初始化(僅加載) |
Class.forName() | Class<?> clazz = Class.forName("com.example.User"); | 僅需類的全限定名,會觸發(fā)類的初始化(執(zhí)行靜態(tài)代碼塊),適合動態(tài)加載類 |
3. Class 類的核心方法
Class類提供了大量方法用于獲取類的元數(shù)據(jù),核心方法如下:
- 獲取類名:
getName()(全限定名)、getSimpleName()(簡單類名)- 獲取構造器:
getConstructor(Class<?>...)(公共構造器)、getDeclaredConstructor(Class<?>...)(所有構造器,包括私有)- 獲取方法:
getMethod(String, Class<?>...)(公共方法,包括繼承的)、getDeclaredMethod(String, Class<?>...)(本類所有方法,包括私有)- 獲取屬性:
getField(String)(公共屬性,包括繼承的)、getDeclaredField(String)(本類所有屬性,包括私有)- 判斷類類型:
isInterface()、isEnum()、isArray()等
4. 示例:通過 Class 對象獲取類信息
public class User {
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello, " + name);
}
}
// 測試類
public class ReflectionDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 獲取Class對象(3種方式任選)
Class<?> clazz = Class.forName("com.example.User");
// 獲取類名
System.out.println("全限定名:" + clazz.getName()); // com.example.User
System.out.println("簡單類名:" + clazz.getSimpleName()); // User
// 獲取所有公共構造器
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> c : constructors) {
System.out.println("公共構造器:" + c);
}
// 獲取所有公共方法
Method[] methods = clazz.getMethods();
for (Method m : methods) {
System.out.println("公共方法:" + m);
}
}
}
5. 圖解 Class 類的角色

上圖展示了核心關系:
- 每個類(如
User)在 JVM 中對應唯一的Class對象;- 類的所有實例(
user1、user2)都可以通過getClass()獲取同一個Class對象;Class對象存儲了類的完整元數(shù)據(jù),是反射的 “入口”。
二、構造方法的 “操縱者”:Constructor 類
Constructor類用于描述類的構造方法,通過它可以在運行時創(chuàng)建類的實例(即使是私有構造方法)。
1. 獲取 Constructor 對象
通過Class對象的方法獲取Constructor:
getConstructor(Class<?>... parameterTypes):獲取公共構造器(參數(shù)為構造器的參數(shù)類型);getDeclaredConstructor(Class<?>... parameterTypes):獲取所有構造器(包括私有);getConstructors():獲取所有公共構造器(返回數(shù)組);getDeclaredConstructors():獲取所有構造器(包括私有,返回數(shù)組)。
2. 創(chuàng)建對象:newInstance ()
獲取Constructor對象后,調用newInstance(Object... initArgs)方法即可創(chuàng)建實例,參數(shù)為構造方法的入?yún)ⅰ?/p>
注意:如果是私有構造器,需要先調用setAccessible(true)突破訪問權限(否則會拋IllegalAccessException)。
3. 示例:通過 Constructor 創(chuàng)建對象
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = User.class;
// 獲取無參構造器(公共)
Constructor<?> constructor1 = clazz.getConstructor();
User user1 = (User) constructor1.newInstance(); // 等價于 new User()
// 獲取有參構造器(公共)
Constructor<?> constructor2 = clazz.getConstructor(String.class, int.class);
User user2 = (User) constructor2.newInstance("張三", 20); // 等價于 new User("張三", 20)
// 獲取私有構造器(假設User有一個私有構造器:private User(String name))
Constructor<?> constructor3 = clazz.getDeclaredConstructor(String.class);
constructor3.setAccessible(true); // 開啟訪問權限
User user3 = (User) constructor3.newInstance("李四"); // 成功創(chuàng)建私有構造器實例
}
}
4. 圖解 Constructor 的作用

上圖展示:
Class對象包含類的所有構造器(通過Constructor對象表示);- 每個
Constructor對象對應一個構造方法,通過newInstance()可創(chuàng)建實例;- 私有構造器需要通過
setAccessible(true)開啟訪問權限。
三、方法的 “執(zhí)行者”:Method 類
Method類用于描述類的成員方法,通過它可以在運行時調用任意方法(包括私有方法和靜態(tài)方法)。
1. 獲取 Method 對象
通過Class對象的方法獲取Method:
getMethod(String name, Class<?>... parameterTypes):獲取公共方法(包括繼承的,參數(shù)為方法名和參數(shù)類型);getDeclaredMethod(String name, Class<?>... parameterTypes):獲取本類所有方法(包括私有,不包括繼承的);getMethods():獲取所有公共方法(包括繼承的,返回數(shù)組);getDeclaredMethods():獲取本類所有方法(包括私有,返回數(shù)組)。
2. 調用方法:invoke ()
獲取Method對象后,調用invoke(Object obj, Object... args)方法即可執(zhí)行方法:
obj:調用方法的實例(靜態(tài)方法可傳null);args:方法的入?yún)ⅰ?/li>
注意:私有方法需要先調用setAccessible(true)突破權限。
3. 示例:通過 Method 調用方法
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = User.class;
User user = new User("張三", 20);
// 獲取公共實例方法sayHello()
Method sayHelloMethod = clazz.getMethod("sayHello");
sayHelloMethod.invoke(user); // 輸出:Hello, 張三
// 獲取私有方法(假設User有私有方法:private void setAge(int age))
Method setAgeMethod = clazz.getDeclaredMethod("setAge", int.class);
setAgeMethod.setAccessible(true); // 開啟訪問權限
setAgeMethod.invoke(user, 25); // 調用私有方法
// 獲取靜態(tài)方法(假設User有靜態(tài)方法:public static void showVersion())
Method showVersionMethod = clazz.getMethod("showVersion");
showVersionMethod.invoke(null); // 靜態(tài)方法obj傳null
}
}
4. 圖解 Method 的作用

上圖展示:
Class對象包含類的所有方法(通過Method對象表示);- 調用實例方法時,
invoke()的第一個參數(shù)為實例對象;- 調用靜態(tài)方法時,
invoke()的第一個參數(shù)為null。
四、屬性的 “讀寫器”:Field 類
Field類用于描述類的成員屬性,通過它可以在運行時讀寫任意屬性(包括私有屬性)。
1. 獲取 Field 對象
通過Class對象的方法獲取Field:
getField(String name):獲取公共屬性(包括繼承的,參數(shù)為屬性名);getDeclaredField(String name):獲取本類所有屬性(包括私有,不包括繼承的);getFields():獲取所有公共屬性(包括繼承的,返回數(shù)組);getDeclaredFields():獲取本類所有屬性(包括私有,返回數(shù)組)。
2. 讀寫屬性:get () 和 set ()
get(Object obj):獲取對象obj的該屬性值(靜態(tài)屬性obj傳null);set(Object obj, Object value):設置對象obj的該屬性值(靜態(tài)屬性obj傳null)。
注意:私有屬性需要先調用setAccessible(true)突破權限。
3. 示例:通過 Field 讀寫屬性
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = User.class;
User user = new User("張三", 20);
// 獲取私有屬性name
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 開啟訪問權限
String name = (String) nameField.get(user); // 讀值:張三
nameField.set(user, "李四"); // 設值
// 獲取私有屬性age
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
int age = (int) ageField.get(user); // 讀值:20
ageField.set(user, 25); // 設值
// 獲取靜態(tài)屬性(假設User有靜態(tài)屬性:public static String version)
Field versionField = clazz.getField("version");
String version = (String) versionField.get(null); // 靜態(tài)屬性obj傳null
versionField.set(null, "1.0.1");
}
}
4. 圖解 Field 的作用

上圖展示:
Class對象包含類的所有屬性(通過Field對象表示);- 讀寫實例屬性時,
get()/set()的參數(shù)為實例對象;- 讀寫靜態(tài)屬性時,
get()/set()的參數(shù)為null。
五、反射的優(yōu)缺點與應用場景
優(yōu)點
- 動態(tài)性:運行時獲取類信息并操作,突破編譯期限制(如動態(tài)加載未知類);
- 靈活性:可操作私有成員,適合框架開發(fā)(如 Spring 的依賴注入);
- 通用性:統(tǒng)一處理不同類的對象(如 ORM 框架映射數(shù)據(jù)庫字段)。
缺點
- 性能開銷:反射操作繞過編譯期檢查,比直接調用慢(約 10-100 倍);
- 安全性問題:
setAccessible(true)可突破訪問權限,可能破壞封裝性; - 代碼可讀性差:反射代碼較繁瑣,不如直接調用直觀。
典型應用場景
- 框架底層:Spring IOC(通過反射創(chuàng)建 Bean)、MyBatis(通過反射映射結果集);
- 注解處理:JUnit 的
@Test、Spring 的@Autowired(通過反射解析注解);- 動態(tài)代理:AOP 的實現(xiàn)基礎(通過反射增強方法);
- 序列化 / 反序列化:JSON 框架(如 Jackson)通過反射讀寫對象屬性。
六、總結
反射機制的四大核心類分工明確:
Class:反射的入口,存儲類的元數(shù)據(jù);Constructor:操縱構造方法,創(chuàng)建對象;Method:執(zhí)行任意方法(包括私有、靜態(tài));Field:讀寫任意屬性(包括私有、靜態(tài))。
掌握反射不僅能理解框架底層原理,更能在需要動態(tài)編程的場景中(如工具類開發(fā))發(fā)揮巨大作用。但需注意:反射是 “雙刃劍”,應避免在性能敏感場景濫用,且需謹慎處理訪問權限問題。
到此這篇關于Java反射機制核心類Class、Constructor、Method、Field的文章就介紹到這了,更多相關Java Class、Constructor、Method、Field內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

