首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Socket 傳遞物件完整指南:物件序列化與 RMI 替代方案實戰

     編輯:Java 相關知識

Java RMI 雖簡化分散式物件通訊,但網路開銷較大。結合底層 Socket 與物件序列化,可構建高效、輕量的物件傳遞機制,有效替代 RMI。本文詳細解析序列化原理、實作步驟、常見陷阱與完整客戶端/伺服端範例。

物件序列化核心機制

實作 java.io.Serializable 標記介面(無方法),即告知 JVM 該類別可序列化。核心類別:

  • ObjectOutputStream:writeObject(Object) 寫入物件
  • ObjectInputStream:readObject() 讀取並重建物件

關鍵要求:被序列化物件的所有非 transient 欄位類別必須同樣實作 Serializable。

序列化現有類別:Date 範例

寫入檔案

FileOutputStream fos = new FileOutputStream("date.out");
ObjectOutputStream oos = new ObjectOutputStream(fos);
Date date = new Date();
oos.writeObject(date);
oos.flush(); oos.close(); fos.close();

讀取還原

FileInputStream fis = new FileInputStream("date.out");
ObjectInputStream ois = new ObjectInputStream(fis);
Date date = (Date) ois.readObject();
System.out.println("The date is: " + date);
ois.close(); fis.close();

判斷類別是否可序列化

使用 JDK serialver 工具:

C:\> serialver java.util.Date
java.util.Date: static final long serialVersionUID = 7523967970034938905L;

輸出 serialVersionUID 表示可序列化;若報錯則不可。圖形介面執行 serialver -show 亦可查詢。

注意:並非所有 JDK 類別皆可序列化(如 Socket、Thread、InputStream 等涉及原生資源的類別)。

自訂類別序列化:UserInfo 完整範例

定義可序列化類別

public class UserInfo implements Serializable {
    String name;
    public UserInfo(String name) { this.name = name; }
    public void printInfo() { System.out.println("The name is: " + name); }
}

寫入多個物件

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("name.out"));
UserInfo user1 = new UserInfo("Java Duke");
UserInfo user2 = new UserInfo("Java Blue");
oos.writeObject(user1);
oos.writeObject(user2); // 可多次呼叫寫入多個物件
oos.flush(); oos.close();

讀取多個物件

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("name.out"));
UserInfo user1 = (UserInfo) ois.readObject();
UserInfo user2 = (UserInfo) ois.readObject(); // 按寫入順序讀取
user1.printInfo();
user2.printInfo();
ois.close();

Socket 傳遞物件:客戶端/伺服端架構

伺服端(接收物件)

ServerSocket server = new ServerSocket(8888);
while (true) {
    Socket socket = server.accept();
    ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
    UserInfo user = (UserInfo) ois.readObject();
    user.printInfo(); // 處理業務邏輯
    ois.close(); socket.close();
}

客戶端(發送物件)

Socket socket = new Socket("localhost", 8888);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
UserInfo user = new UserInfo("Network User");
oos.writeObject(user);
oos.flush();
oos.close(); socket.close();

關鍵最佳實踐與陷阱

  1. serialVersionUID 顯式宣告:避免跨版本反序列化失敗
    private static final long serialVersionUID = 1L;
    
  2. transient 關鍵字:排除不需序列化的欄位(如連線、快取、敏感資料)
  3. 版本演進相容性:僅新增欄位相容;刪除/修改欄位類型需謹慎規劃
  4. 安全性考量:反序列化不可信資料極度危險(RCE 風險),生產環境需驗證來源或使用安全框架
  5. 效能優化:大量資料傳輸考慮 Externalizable 或 Protobuf、Avro 等二進位協議

總結

Socket + 序列化提供輕量級物件傳遞能力,適用於內部服務通訊、快取同步、分散式計算節點協作等場景。但需嚴格把控序列化相容性與安全性,複雜系統建議評估成熟 RPC 框架(gRPC、Dubbo)以獲得更完善的治理能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved