Java反射機(jī)制核心類Class、Constructor、Method、Field詳解

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

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

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

上圖展示:
Class對象包含類的所有方法(通過Method對象表示);- 調(diào)用實(shí)例方法時(shí),
invoke()的第一個(gè)參數(shù)為實(shí)例對象;- 調(diào)用靜態(tài)方法時(shí),
invoke()的第一個(gè)參數(shù)為null。
四、屬性的 “讀寫器”:Field 類
Field類用于描述類的成員屬性,通過它可以在運(yùn)行時(shí)讀寫任意屬性(包括私有屬性)。
1. 獲取 Field 對象
通過Class對象的方法獲取Field:
getField(String name):獲取公共屬性(包括繼承的,參數(shù)為屬性名);getDeclaredField(String name):獲取本類所有屬性(包括私有,不包括繼承的);getFields():獲取所有公共屬性(包括繼承的,返回?cái)?shù)組);getDeclaredFields():獲取本類所有屬性(包括私有,返回?cái)?shù)組)。
2. 讀寫屬性:get () 和 set ()
get(Object obj):獲取對象obj的該屬性值(靜態(tài)屬性obj傳null);set(Object obj, Object value):設(shè)置對象obj的該屬性值(靜態(tài)屬性obj傳null)。
注意:私有屬性需要先調(diào)用setAccessible(true)突破權(quán)限。
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); // 開啟訪問權(quán)限
String name = (String) nameField.get(user); // 讀值:張三
nameField.set(user, "李四"); // 設(shè)值
// 獲取私有屬性age
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
int age = (int) ageField.get(user); // 讀值:20
ageField.set(user, 25); // 設(shè)值
// 獲取靜態(tài)屬性(假設(shè)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對象表示);- 讀寫實(shí)例屬性時(shí),
get()/set()的參數(shù)為實(shí)例對象;- 讀寫靜態(tài)屬性時(shí),
get()/set()的參數(shù)為null。
五、反射的優(yōu)缺點(diǎn)與應(yīng)用場景
優(yōu)點(diǎn)
- 動(dòng)態(tài)性:運(yùn)行時(shí)獲取類信息并操作,突破編譯期限制(如動(dòng)態(tài)加載未知類);
- 靈活性:可操作私有成員,適合框架開發(fā)(如 Spring 的依賴注入);
- 通用性:統(tǒng)一處理不同類的對象(如 ORM 框架映射數(shù)據(jù)庫字段)。
缺點(diǎn)
- 性能開銷:反射操作繞過編譯期檢查,比直接調(diào)用慢(約 10-100 倍);
- 安全性問題:
setAccessible(true)可突破訪問權(quán)限,可能破壞封裝性; - 代碼可讀性差:反射代碼較繁瑣,不如直接調(diào)用直觀。
典型應(yīng)用場景
- 框架底層:Spring IOC(通過反射創(chuàng)建 Bean)、MyBatis(通過反射映射結(jié)果集);
- 注解處理:JUnit 的
@Test、Spring 的@Autowired(通過反射解析注解);- 動(dòng)態(tài)代理:AOP 的實(shí)現(xiàn)基礎(chǔ)(通過反射增強(qiáng)方法);
- 序列化 / 反序列化:JSON 框架(如 Jackson)通過反射讀寫對象屬性。
六、總結(jié)
反射機(jī)制的四大核心類分工明確:
Class:反射的入口,存儲類的元數(shù)據(jù);Constructor:操縱構(gòu)造方法,創(chuàng)建對象;Method:執(zhí)行任意方法(包括私有、靜態(tài));Field:讀寫任意屬性(包括私有、靜態(tài))。
掌握反射不僅能理解框架底層原理,更能在需要?jiǎng)討B(tài)編程的場景中(如工具類開發(fā))發(fā)揮巨大作用。但需注意:反射是 “雙刃劍”,應(yīng)避免在性能敏感場景濫用,且需謹(jǐn)慎處理訪問權(quán)限問題。
到此這篇關(guān)于Java反射機(jī)制核心類Class、Constructor、Method、Field的文章就介紹到這了,更多相關(guān)Java Class、Constructor、Method、Field內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis中的@Param及動(dòng)態(tài)SQL詳解
這篇文章主要介紹了Mybatis中的@Param及動(dòng)態(tài)SQL詳解,@Param是MyBatis所提供的作為Dao層的注解,作用是用于傳遞參數(shù),從而可以與SQL中的的字段名相對應(yīng),需要的朋友可以參考下2023-10-10
SpringBoot+Apache tika實(shí)現(xiàn)文檔內(nèi)容解析的示例詳解
Apache tika是Apache開源的一個(gè)文檔解析工具,本文主要為大家介紹了如何在springboot中引入tika的方式解析文檔,感興趣的小伙伴可以了解一下2023-07-07
解決IntelliJ IDEA中鼠標(biāo)拖動(dòng)選擇為矩形區(qū)域問題
這篇文章主要介紹了解決IntelliJ IDEA中鼠標(biāo)拖動(dòng)選擇為矩形區(qū)域問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10

