Java RMI 雖簡化分散式物件通訊,但網路開銷較大。結合底層 Socket 與物件序列化,可構建高效、輕量的物件傳遞機制,有效替代 RMI。本文詳細解析序列化原理、實作步驟、常見陷阱與完整客戶端/伺服端範例。
實作 java.io.Serializable 標記介面(無方法),即告知 JVM 該類別可序列化。核心類別:
ObjectOutputStream:writeObject(Object) 寫入物件ObjectInputStream:readObject() 讀取並重建物件關鍵要求:被序列化物件的所有非 transient 欄位類別必須同樣實作 Serializable。
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 等涉及原生資源的類別)。
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();
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();
private static final long serialVersionUID = 1L;
Externalizable 或 Protobuf、Avro 等二進位協議Socket + 序列化提供輕量級物件傳遞能力,適用於內部服務通訊、快取同步、分散式計算節點協作等場景。但需嚴格把控序列化相容性與安全性,複雜系統建議評估成熟 RPC 框架(gRPC、Dubbo)以獲得更完善的治理能力。