Java 序列化和Java反射的底層原理及區(qū)別對(duì)比分析
Java 序列化與反射:底層原理與核心區(qū)別
Java 序列化和反射是 Java 中兩個(gè)不同維度的機(jī)制,序列化聚焦對(duì)象的持久化與傳輸,反射聚焦類 / 對(duì)象的動(dòng)態(tài)訪問(wèn)與操作,二者底層原理和應(yīng)用場(chǎng)景差異顯著,以下從底層原理、核心特性、區(qū)別對(duì)比展開解析:
一、Java 序列化:底層原理與機(jī)制
1. 定義與核心目標(biāo)
序列化是將對(duì)象的狀態(tài)信息(屬性值)轉(zhuǎn)換為字節(jié)序列的過(guò)程,反序列化則是將字節(jié)序列恢復(fù)為對(duì)象的過(guò)程。核心目標(biāo)是實(shí)現(xiàn)對(duì)象的持久化(如存文件)、網(wǎng)絡(luò)傳輸(如 RPC 通信)或跨進(jìn)程共享。
2. 底層原理
(1)序列化的核心流程
- 標(biāo)記可序列化:類需實(shí)現(xiàn)
java.io.Serializable接口(標(biāo)記接口,無(wú)方法,僅標(biāo)識(shí)類可被序列化); - 對(duì)象狀態(tài)轉(zhuǎn)換:JVM 通過(guò)序列化機(jī)制遍歷對(duì)象的非靜態(tài)屬性(static、transient 修飾的屬性不序列化),將屬性值轉(zhuǎn)換為字節(jié)序列;
- 處理引用關(guān)系:若對(duì)象引用其他可序列化對(duì)象,會(huì)遞歸序列化引用對(duì)象,通過(guò)
serialVersionUID保證序列化與反序列化的類版本一致性。
(2)關(guān)鍵細(xì)節(jié)
- serialVersionUID:類的版本號(hào),序列化時(shí)寫入字節(jié)序列,反序列化時(shí)校驗(yàn)版本號(hào)是否一致,不一致則拋出
InvalidClassException; - transient 關(guān)鍵字:修飾的屬性不參與序列化(如敏感數(shù)據(jù)、臨時(shí)狀態(tài));
- 自定義序列化:通過(guò)重寫
writeObject()/readObject()方法自定義序列化邏輯(如加密敏感屬性); - Externalizable 接口:替代
Serializable,需手動(dòng)實(shí)現(xiàn)writeExternal()/readExternal(),完全控制序列化過(guò)程。
(3)底層實(shí)現(xiàn)(JVM 層面)
序列化由ObjectOutputStream實(shí)現(xiàn),底層通過(guò)反射獲取對(duì)象的類信息和屬性值,按特定格式(如魔數(shù)、版本號(hào)、類名、屬性類型 / 值)寫入字節(jié)流;反序列化由ObjectInputStream實(shí)現(xiàn),讀取字節(jié)流并反射創(chuàng)建對(duì)象、恢復(fù)屬性值。
3. 示例代碼
import java.io.*;
// 實(shí)現(xiàn)Serializable接口
class User implements Serializable {
private static final long serialVersionUID = 1L; // 版本號(hào)
private String name;
private transient int age; // transient修飾,不序列化
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + "}";
}
}
public class SerializationDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 序列化:對(duì)象→字節(jié)序列(存文件)
User user = new User("Alice", 20);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"));
oos.writeObject(user);
oos.close();
// 反序列化:字節(jié)序列→對(duì)象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"));
User deserializedUser = (User) ois.readObject();
ois.close();
System.out.println(deserializedUser); // 輸出:User{name='Alice', age=0}(age未序列化)
}
}二、Java 反射:底層原理與機(jī)制
1. 定義與核心目標(biāo)
反射是指程序在運(yùn)行時(shí)動(dòng)態(tài)獲取類的信息(如類名、屬性、方法),并動(dòng)態(tài)調(diào)用對(duì)象的方法、訪問(wèn)屬性的機(jī)制。核心目標(biāo)是打破封裝,實(shí)現(xiàn)對(duì)類 / 對(duì)象的動(dòng)態(tài)操作(如框架的靈活擴(kuò)展)。
2. 底層原理
(1)反射的核心基礎(chǔ)
- Class 對(duì)象:每個(gè)類加載后,JVM 會(huì)為其創(chuàng)建一個(gè)
Class對(duì)象(存儲(chǔ)類的元數(shù)據(jù):屬性、方法、構(gòu)造器等),反射通過(guò)Class對(duì)象訪問(wèn)類的信息; - 類加載機(jī)制:反射依賴類加載器(ClassLoader)加載類,可通過(guò)
Class.forName()、對(duì)象.getClass()、類名.class獲取Class對(duì)象。
(2)反射的核心流程
- 獲取 Class 對(duì)象:通過(guò)三種方式獲取目標(biāo)類的
Class實(shí)例; - 訪問(wèn)類成員:通過(guò)
Class對(duì)象的方法(如getFields()、getMethods()、getConstructors())獲取屬性、方法、構(gòu)造器的Field/Method/Constructor對(duì)象; - 動(dòng)態(tài)操作:通過(guò)
Field.set()/get()訪問(wèn)屬性值,Method.invoke()調(diào)用方法,Constructor.newInstance()創(chuàng)建對(duì)象(可突破訪問(wèn)修飾符限制,如訪問(wèn) private 成員)。
(3)底層實(shí)現(xiàn)(JVM 層面)
JVM 在類加載時(shí)生成Class對(duì)象,存儲(chǔ)在方法區(qū)(元空間),反射通過(guò)本地方法(native)調(diào)用 JVM 的底層接口,直接訪問(wèn)Class對(duì)象的元數(shù)據(jù),繞過(guò)編譯期的訪問(wèn)檢查(如通過(guò)setAccessible(true)打破封裝)。
3. 示例代碼
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private void sayHello() {
System.out.println("Hello, " + name);
}
}
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
// 1. 獲取Class對(duì)象
Class<?> personClass = Person.class;
// 2. 通過(guò)反射創(chuàng)建對(duì)象(調(diào)用構(gòu)造器)
Constructor<?> constructor = personClass.getConstructor(String.class, int.class);
Object person = constructor.newInstance("Bob", 25);
// 3. 訪問(wèn)private屬性
Field nameField = personClass.getDeclaredField("name");
nameField.setAccessible(true); // 打破封裝
System.out.println("Name: " + nameField.get(person)); // 輸出:Name: Bob
// 4. 調(diào)用private方法
Method sayHelloMethod = personClass.getDeclaredMethod("sayHello");
sayHelloMethod.setAccessible(true);
sayHelloMethod.invoke(person); // 輸出:Hello, Bob
}
}三、序列化與反射的核心區(qū)別
| 維度 | Java 序列化 | Java 反射 |
|---|---|---|
| 核心目標(biāo) | 對(duì)象的持久化、傳輸(狀態(tài)保存與恢復(fù)) | 運(yùn)行時(shí)動(dòng)態(tài)訪問(wèn) / 操作類 / 對(duì)象(打破封裝) |
| 底層聚焦 | 對(duì)象狀態(tài)的字節(jié)轉(zhuǎn)換 | 類元數(shù)據(jù)的動(dòng)態(tài)訪問(wèn) |
| 依賴機(jī)制 | 實(shí)現(xiàn)Serializable接口,JVM 序列化規(guī)則 | 依賴Class對(duì)象,反射 API(java.lang.reflect) |
| 操作對(duì)象 | 對(duì)象的屬性值(非靜態(tài)、非 transient) | 類的屬性、方法、構(gòu)造器等成員 |
| 訪問(wèn)權(quán)限 | 僅訪問(wèn)可序列化的屬性(受修飾符限制) | 可突破訪問(wèn)修飾符(setAccessible(true)) |
| 應(yīng)用場(chǎng)景 | 分布式通信(RPC)、對(duì)象持久化(文件 / 數(shù)據(jù)庫(kù)) | 框架開發(fā)(Spring/IOC、MyBatis)、動(dòng)態(tài)代理、工具類(如 JSON 解析) |
| 性能開銷 | 序列化 / 反序列化需遍歷對(duì)象引用,開銷中等 | 反射需繞過(guò)編譯期檢查,性能低于直接調(diào)用(可通過(guò)緩存優(yōu)化) |
| 版本兼容性 | 依賴serialVersionUID保證版本一致 | 無(wú)版本問(wèn)題,依賴類加載的元數(shù)據(jù) |
四、關(guān)聯(lián)與總結(jié)
- 關(guān)聯(lián):序列化底層依賴反射獲取對(duì)象的類信息和屬性值;反射可用于自定義序列化邏輯(如通過(guò)反射遍歷屬性實(shí)現(xiàn)自定義序列化)。
- 核心區(qū)別:序列化是 “對(duì)象狀態(tài)的轉(zhuǎn)換與恢復(fù)”,反射是 “類 / 對(duì)象的動(dòng)態(tài)訪問(wèn)與操作”;序列化解決對(duì)象的傳輸與持久化問(wèn)題,反射解決程序的動(dòng)態(tài)性與靈活性問(wèn)題。
理解二者的關(guān)鍵在于:序列化關(guān)注對(duì)象的狀態(tài),反射關(guān)注類的結(jié)構(gòu),二者雖底層都依賴 JVM 的類元數(shù)據(jù),但目標(biāo)和應(yīng)用場(chǎng)景完全不同。
到此這篇關(guān)于Java 序列化和Java反射的底層原理以及區(qū)別?的文章就介紹到這了,更多相關(guān)java序列化和反射內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合Ehcache3的實(shí)現(xiàn)步驟
本文主要介紹了SpringBoot整合Ehcache3的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
Kotlin基礎(chǔ)教程之dataclass,objectclass,use函數(shù),類擴(kuò)展,socket
這篇文章主要介紹了Kotlin基礎(chǔ)教程之dataclass,objectclass,use函數(shù),類擴(kuò)展,socket的相關(guān)資料,需要的朋友可以參考下2017-05-05
Mybatis-plus使用TableNameHandler分表詳解(附完整示例源碼)
這篇文章主要介紹了Mybatis-plus使用TableNameHandler分表詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01

