CLDC 不支援 Java 標準序列化 (Serializable),但我們可自行實作輕量級序列化,透過 DataOutputStream/DataInputStream 進行物件與位元組陣列的雙向轉換,實現高效的網路資料傳輸與 RMS 儲存。
定義資料模型類別,提供 serialize() 與 deserialize() 靜態方法,負責將物件欄位按固定順序寫入/讀出資料流。此方式不依賴 Reflection,效能優異,且雙端協定一致即可互通。
package com.j2me.dev;
import java.io.*;
public class Account {
private String userName = "";
private String email = "";
private int age = 0;
private boolean gender = false; // false=女, true=男
public Account() {}
public Account(String userName, String email, int age, boolean gender) {
this.userName = userName;
this.email = email;
this.age = age;
this.gender = gender;
}
// 序列化:寫入 DataOutputStream
public void serialize(DataOutputStream dos) throws IOException {
dos.writeUTF(userName);
dos.writeUTF(email);
dos.writeInt(age);
dos.writeBoolean(gender);
}
// 反序列化:從 DataInputStream 重建物件
public static Account deserialize(DataInputStream dis) throws IOException {
Account acc = new Account();
acc.userName = dis.readUTF();
acc.email = dis.readUTF();
acc.age = dis.readInt();
acc.gender = dis.readBoolean();
return acc;
}
public String toString() {
return "UserName=" + userName + ", Email=" + email +
", Age=" + age + ", Gender=" + (gender ? "Male" : "Female");
}
}
private void sendAccount(Account account) {
new Thread() {
public void run() {
HttpConnection conn = null;
DataOutputStream dos = null;
try {
conn = (HttpConnection) Connector.open(SERVER_URL);
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("Content-Type", "application/octet-stream");
dos = new DataOutputStream(conn.openOutputStream());
account.serialize(dos);
dos.flush();
// 讀取伺服器回應...
} catch (IOException e) {
e.printStackTrace();
} finally {
closeQuietly(dos);
closeQuietly(conn);
}
}
}.start();
}
public class AccountServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
DataInputStream dis = new DataInputStream(req.getInputStream());
Account account = Account.deserialize(dis);
System.out.println("Received: " + account);
// 業務邏輯處理...
resp.setStatus(HttpServletResponse.SC_OK);
}
}
public class RegisterMIDlet extends MIDlet implements CommandListener {
private Form form;
private TextField nameField, emailField, ageField;
private ChoiceGroup genderGroup;
private NetworkThread netThread;
protected void startApp() {
form = new Form("註冊");
nameField = new TextField("姓名", "", 20, TextField.ANY);
emailField = new TextField("Email", "", 30, TextField.EMAILADDR);
ageField = new TextField("年齡", "", 3, TextField.NUMERIC);
genderGroup = new ChoiceGroup("性別", Choice.EXCLUSIVE);
genderGroup.append("男", null);
genderGroup.append("女", null);
form.append(nameField);
form.append(emailField);
form.append(ageField);
form.append(genderGroup);
Command submit = new Command("送出", Command.OK, 1);
Command exit = new Command("離開", Command.EXIT, 2);
form.addCommand(submit);
form.addCommand(exit);
form.setCommandListener(this);
Display.getDisplay(this).setCurrent(form);
netThread = new NetworkThread(this);
netThread.start();
}
public void commandAction(Command c, Displayable d) {
if (c == exit) {
destroyApp(false);
notifyDestroyed();
} else if (c == submit) {
String name = nameField.getString();
String email = emailField.getString();
int age = Integer.parseInt(ageField.getString());
boolean gender = (genderGroup.getSelectedIndex() == 0);
Account acc = new Account(name, email, age, gender);
netThread.sendAccount(acc);
}
}
}
class NetworkThread extends Thread {
private RegisterMIDlet midlet;
private Account pendingAccount;
private boolean running = true;
public NetworkThread(RegisterMIDlet midlet) {
this.midlet = midlet;
}
public synchronized void sendAccount(Account acc) {
pendingAccount = acc;
notify();
}
public void run() {
while (running) {
synchronized (this) {
while (pendingAccount == null && running) {
try { wait(); } catch (InterruptedException e) {}
}
}
if (!running) break;
Account acc = pendingAccount;
pendingAccount = null;
sendToServer(acc);
}
}
private void sendToServer(Account acc) { /* HTTP POST 實作 */ }
}
Account 類別定義(套件名可不同)writeUTF/readUTF(修改版 UTF-8),支援 Unicodeint 4 bytes、long 8 bytes這種自訂序列化模式是 J2ME 時代的經典做法,同樣適用於現代 Java ME、嵌入式系統或任何需要輕量二進位協定的場合。