0Pricing
Java Academy · บทเรียน

การทำซีเรียลไลซ์แบบกำหนดเอง: writeObject และ readObject

เขียนทับ writeObject และ readObject เพื่อเข้ารหัส บีบอัด หรือจัดการฟิลด์แบบกำหนดเอง

การทำซีเรียลไลซ์แบบกำหนดเอง: writeObject และ readObject เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

เมื่อการซีเรียลไลซ์เริ่มต้นไม่เพียงพอ

การซีเรียลไลซ์เริ่มต้นจะบันทึกฟิลด์ที่ไม่ใช่ transient ทั้งหมดตามสภาพเดิม บางครั้งคุณอาจต้องเข้ารหัส บีบอัด หรือใช้รูปแบบอื่น นั่นคือจุดที่กลไก writeObject / readObject เข้ามามีบทบาท

การประกาศ writeObject

เพิ่มเมธอด private void writeObject(ObjectOutputStream oos) Java จะเรียกใช้เมธอดนี้แทนกลไกเริ่มต้น คุณจึงควบคุมได้อย่างแม่นยำว่าข้อมูลใดจะถูกเขียน

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject(); // write non-transient fields normally
    oos.writeUTF(encrypt(this.secret)); // write encrypted secret
}

การประกาศ readObject

เพิ่มเมธอด private void readObject(ObjectInputStream ois) Java จะเรียกใช้เมธอดนี้ระหว่างการดีซีเรียลไลซ์ คุณต้องอ่านข้อมูลตามลำดับเดียวกับที่เขียนไว้ทุกประการ

private void readObject(ObjectInputStream ois)
        throws IOException, ClassNotFoundException {
    ois.defaultReadObject(); // restore non-transient fields
    this.secret = decrypt(ois.readUTF()); // decrypt and restore
}

ลำดับมีความสำคัญ

สิ่งใดก็ตามที่เขียนใน writeObject ต้องอ่านกลับใน ลำดับเดียวกัน ใน readObject หากลำดับไม่ตรงกันจะเกิด StreamCorruptedException

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.writeInt(version);
    oos.writeUTF(data);
}
private void readObject(ObjectInputStream ois)
        throws IOException, ClassNotFoundException {
    this.version = ois.readInt();  // same order
    this.data    = ois.readUTF();
}

การบีบอัดข้อมูลระหว่างการซีเรียลไลซ์

ห่อสตรีมด้วย GZIPOutputStream ภายใน writeObject เพื่อบีบอัดฟิลด์ขนาดใหญ่ แล้วใช้ GZIPInputStream ภายใน readObject เพื่อคลายการบีบอัด

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject();
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try (GZIPOutputStream gz = new GZIPOutputStream(bos)) {
        gz.write(largePayload.getBytes());
    }
    oos.writeObject(bos.toByteArray());
}

กลไก readResolve

readResolve() จะถูกเรียกหลังการดีซีเรียลไลซ์ ให้คืนค่าอ็อบเจ็กต์ทดแทน ซึ่งมีประโยชน์สำหรับซิงเกิลตันและ enum เพื่อให้แน่ใจว่าหลังการดีซีเรียลไลซ์จะมีอินสแตนซ์อยู่เพียงหนึ่งเดียว

public class AppConfig implements Serializable {
    private static final AppConfig INSTANCE = new AppConfig();
    private AppConfig() {}
    public static AppConfig getInstance() { return INSTANCE; }
    private Object readResolve() { return INSTANCE; } // return singleton
}

กลไก writeReplace

writeReplace() จะถูกเรียกก่อนการซีเรียลไลซ์ ให้คืนค่าอ็อบเจ็กต์อื่นที่จะถูกซีเรียลไลซ์แทน ซึ่งมีประโยชน์สำหรับรูปแบบพร็อกซีและอ็อบเจ็กต์ตัวแทนสำหรับการซีเรียลไลซ์

private Object writeReplace() {
    return new UserProxy(this.id); // serialize a lightweight proxy
}

การตรวจสอบฟิลด์ใน readObject

คุณสามารถเพิ่มตรรกะตรวจสอบความถูกต้องภายใน readObject เพื่อปฏิเสธข้อมูลที่ไม่ถูกต้องหรือถูกแก้ไขโดยมิชอบ ซึ่งเป็นส่วนหนึ่งของกลยุทธ์การป้องกันหลายชั้น

private void readObject(ObjectInputStream ois)
        throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    if (age < 0 || age > 150) {
        throw new InvalidObjectException("Invalid age: " + age);
    }
}

การจัดการการเปลี่ยนแปลงเวอร์ชัน

ใช้ฟิลด์เวอร์ชันใน writeObject เพื่อให้ readObject รองรับทั้งรูปแบบเก่าและใหม่ได้อย่างราบรื่นระหว่างการย้ายระบบ

private static final int SERIAL_VERSION = 2;
private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject();
    oos.writeInt(SERIAL_VERSION);
    if (SERIAL_VERSION >= 2) oos.writeUTF(email); // new field
}
private void readObject(ObjectInputStream ois)
        throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    int v = ois.readInt();
    if (v >= 2) this.email = ois.readUTF();
}

รูปแบบพร็อกซีสำหรับการซีเรียลไลซ์

แนวทางที่แข็งแกร่งคือ เขียนคลาสภายในแบบ static ที่เป็น private ซึ่งเก็บสถานะเท่าที่จำเป็น จากนั้นใช้ writeReplace เพื่อเขียนพร็อกซี และใช้ readResolve ของพร็อกซีเพื่อสร้างอ็อบเจ็กต์ต้นฉบับกลับคืน

ข้อควรพิจารณาด้านประสิทธิภาพ

การซีเรียลไลซ์แบบกำหนดเองเพิ่มค่าใช้จ่ายจากการเรียกเมธอด แต่สามารถลดขนาดข้อมูลได้อย่างมาก ควรทดสอบประสิทธิภาพก่อนปรับให้เหมาะสม และใช้ Externalizable หากต้องการควบคุมสูงสุด

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ลำดับใน writeObject และ readObject ต้องเป็นอย่างไร

สรุปทบทวน

เขียนทับ writeObject / readObject เพื่อเข้ารหัส บีบอัด หรือใช้รูปแบบกำหนดเอง ใช้ readResolve สำหรับซิงเกิลตัน และอ่านข้อมูลตามลำดับเดียวกับที่เขียนเสมอ

คำถามที่พบบ่อย

บทเรียน “การทำซีเรียลไลซ์แบบกำหนดเอง: writeObject และ readObject” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การทำซีเรียลไลซ์แบบกำหนดเอง: writeObject และ readObject” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การทำซีเรียลไลซ์แบบกำหนดเอง: writeObject และ readObject”

เขียนทับ writeObject และ readObject เพื่อเข้ารหัส บีบอัด หรือจัดการฟิลด์แบบกำหนดเอง คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การทำซีเรียลไลซ์แบบกำหนดเอง: writeObject และ readObject” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พื้นฐานการทำซีเรียลไลซ์ของ Java
  2. ฟิลด์ transient และ serialVersionUID
  3. การทำซีเรียลไลซ์แบบกำหนดเอง: writeObject และ readObject
  4. ทางเลือกสมัยใหม่: JSON และ Protocol Buffers
← กลับไปที่ Java Academy