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

J2ME 網路傳輸中的自訂序列化機制實作

     編輯:J2ME

CLDC 不支援 Java 標準序列化 (Serializable),但我們可自行實作輕量級序列化,透過 DataOutputStream/DataInputStream 進行物件與位元組陣列的雙向轉換,實現高效的網路資料傳輸與 RMS 儲存。

核心概念

定義資料模型類別,提供 serialize() 與 deserialize() 靜態方法,負責將物件欄位按固定順序寫入/讀出資料流。此方式不依賴 Reflection,效能優異,且雙端協定一致即可互通。

資料模型:Account 類別

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");
    }
}

客戶端 MIDlet 發送資料

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();
}

伺服器端 Servlet 接收

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);
    }
}

MIDlet 完整範例:使用者註冊表單

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 實作 */ }
}

關鍵優勢

  • 跨平台相容:不依賴 JVM 序列化機制,CLDC/MIDP 皆可用
  • 效能優異:二進位格式體積小、解析快、無 Reflection 開銷
  • 版本彈性:新增欄位只需修改 serialize/deserialize,協定版本號可向前相容
  • 適用 RMS:同樣方法可將物件存入 RecordStore

注意事項

  • 客戶端與伺服器必須使用相同的 Account 類別定義(套件名可不同)
  • 字串使用 writeUTF/readUTF(修改版 UTF-8),支援 Unicode
  • 數值型別固定大小:int 4 bytes、long 8 bytes
  • 生產環境建議加入魔數、版本號、檢查和等協定框架

這種自訂序列化模式是 J2ME 時代的經典做法,同樣適用於現代 Java ME、嵌入式系統或任何需要輕量二進位協定的場合。

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