อะไรคือความแตกต่างระหว่าง Serializable และ Externalizable ใน Java?


คำตอบ:


267

หากต้องการเพิ่มคำตอบอื่น ๆjava.io.Serializableคุณจะได้รับความสามารถในการทำให้เป็นอันดับ "อัตโนมัติ" สำหรับวัตถุในชั้นเรียนของคุณ ไม่จำเป็นต้องใช้ตรรกะอื่นใดมันจะทำงานได้ รันไทม์ Java จะใช้การสะท้อนเพื่อหาวิธีการจัดเรียงและยกเลิกการปิดกั้นวัตถุของคุณ

ใน Java เวอร์ชันก่อนหน้าการสะท้อนช้ามากและกราฟวัตถุขนาดใหญ่แบบอนุกรม (เช่นในแอปพลิเคชันไคลเอนต์เซิร์ฟเวอร์ RMI) เป็นปัญหาประสิทธิภาพเล็กน้อย เพื่อจัดการกับสถานการณ์นี้มีการjava.io.Externalizableจัดเตรียมอินเทอร์เฟซซึ่งเป็นเหมือนjava.io.Serializableแต่มีกลไกที่เขียนขึ้นเองเพื่อดำเนินการฟังก์ชันการจัดเรียงและการยกเลิกการจัดเรียง (คุณจำเป็นต้องใช้งานreadExternalและwriteExternalวิธีการในชั้นเรียน สิ่งนี้ช่วยให้คุณสามารถแก้ไขปัญหาคอขวดของการสะท้อนแสงได้

ใน Java เวอร์ชันล่าสุด (1.3 เป็นต้นไปอย่างแน่นอน) ประสิทธิภาพของการสะท้อนนั้นดีกว่าที่เคยเป็นมาอย่างมากดังนั้นนี่จึงเป็นปัญหาที่น้อยมาก ฉันสงสัยว่าคุณจะถูกกดดันอย่างหนักเพื่อรับผลประโยชน์ที่มีความหมายจากExternalizableJVM ที่ทันสมัย

นอกจากนี้กลไกการทำให้เป็นอันดับของ Java ในตัวไม่ใช่เพียงอย่างเดียวคุณสามารถรับการเปลี่ยนจากบุคคลที่สามเช่น JBoss Serialization ซึ่งเร็วกว่ามากและเป็นการแทนที่แบบหล่นสำหรับค่าเริ่มต้น

ข้อเสียใหญ่Externalizableคือคุณต้องรักษาตรรกะนี้ด้วยตัวเอง - ถ้าคุณเพิ่มลบหรือเปลี่ยนฟิลด์ในชั้นเรียนของคุณคุณต้องเปลี่ยนwriteExternal/ readExternalวิธีการของคุณเพื่อบัญชี

โดยสรุปExternalizableเป็นที่ระลึกของ Java 1.1 วัน ไม่จำเป็นต้องใช้มันอีกแล้ว


61
ไม่เป็นไปตามมาตรฐานเหล่านี้: [ code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking] การทำให้เป็นอนุกรมด้วยตนเอง (โดยใช้ภายนอก) นั้นเร็วกว่าการใช้ซีเรียลไลซ์เซชันเริ่มต้นของจาวามาก ถ้าความเร็วสำคัญกับงานของคุณให้เขียน serializer ของคุณเองอย่างแน่นอน
volni

6
อัปเดตเป็นลิงค์ใหม่github.com/eishay/jvm-serializers/wikiแนะนำโดย @Jack
noquery

3
"คู่มือจาวา" ในgithub.com/eishay/jvm-serializers/wikiไม่ได้ใช้ Externalizable ซึ่งจะบ่งบอกถึงการใช้ ObjectOutputStream ดูgithub.com/eishay/jvm-serializers/wiki/ToolBehaviorสำหรับลิงก์ไปยังรหัส แต่เป็นรหัสที่เขียนด้วยมือซึ่งใช้ DataOutputStream ดังนั้นจึงไม่ประสบกับสิ่งต่าง ๆ ที่ทำให้ ObjectOutputStream ทำงานช้า (เช่นการติดตามอินสแตนซ์ของวัตถุและรองรับวงจรวัตถุ)
Esko Luontola

7
การรักษาตรรกะด้วยตัวคุณเองเป็นเพียงข้อเสียถ้าคลาสไม่เปลี่ยนแปลงและคุณไม่จำเป็นต้องอ่านในเวอร์ชันเก่าของข้อมูลเก่า หากคุณต้องการมีอิสระในการเปลี่ยนชั้นเรียนของคุณได้โดยไม่ต้องเขียนโค้ดอัปรีย์ไป deserialize รุ่นเก่าของมันExternalizableจะช่วยได้มาก
Tim Boudreau

2
ฉันต้องเขียนคอลเลกชันที่กำหนดเองและฉันต้องบอกว่าExternalizableเหมาะกับฉันดีกว่ามากเพราะฉันไม่ต้องการที่จะเอาท์พุทอาร์เรย์ด้วยช่องว่างหรือวัตถุตัวยึดรวมทั้งอินเทอร์เฟซที่ชัดเจนที่คุณสามารถจัดการมรดกได้ -class writeExternal()สามารถเพิ่มล็อครอบการเรียกร้องให้ แน่นอนว่า Externalizable ยังมีความเกี่ยวข้องอย่างมากแน่นอนสำหรับวัตถุขนาดใหญ่หรือซับซ้อน
Haravikk

37

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

  ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("/Users/Desktop/files/temp.txt"));
        oos.writeObject(linkedListHead); //writing head of linked list
        oos.close();

แต่ถ้าคุณต้องการทำให้เป็นอันดับ จำกัด หรือไม่ต้องการให้บางส่วนของวัตถุของคุณเป็นอนุกรมแล้วใช้ Externalizable อินเตอร์เฟส Externalizable ขยายอินเตอร์เฟส Serializable และเพิ่มสองวิธีคือ writeExternal () และ readExternal () สิ่งเหล่านี้ถูกเรียกโดยอัตโนมัติในขณะที่การทำให้เป็นอนุกรมหรือดีซีเรียลไลเซชัน ในขณะที่ทำงานกับ Externalizable เราควรจำไว้ว่าตัวสร้างค่าเริ่มต้นควรเป็นแบบสาธารณะรหัสนั้นจะมีข้อยกเว้น โปรดปฏิบัติตามรหัสด้านล่าง:

public class MyExternalizable implements Externalizable
{

private String userName;
private String passWord;
private Integer roll;

public MyExternalizable()
{

}

public MyExternalizable(String userName, String passWord, Integer roll)
{
    this.userName = userName;
    this.passWord = passWord;
    this.roll = roll;
}

@Override
public void writeExternal(ObjectOutput oo) throws IOException 
{
    oo.writeObject(userName);
    oo.writeObject(roll);
}

@Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException 
{
    userName = (String)oi.readObject();
    roll = (Integer)oi.readObject();
}

public String toString()
{
    StringBuilder b = new StringBuilder();
    b.append("userName: ");
    b.append(userName);
    b.append("  passWord: ");
    b.append(passWord);
    b.append("  roll: ");
    b.append(roll);

    return b.toString();
}
public static void main(String[] args)
{
    try
    {
        MyExternalizable m  = new MyExternalizable("nikki", "student001", 20);
        System.out.println(m.toString());
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/Desktop/files/temp1.txt"));
        oos.writeObject(m);
        oos.close();

        System.out.println("***********************************************************************");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/Desktop/files/temp1.txt"));
        MyExternalizable mm = (MyExternalizable)ois.readObject();
        mm.toString();
        System.out.println(mm.toString());
    } 
    catch (ClassNotFoundException ex) 
    {
        Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
    }
    catch(IOException ex)
    {
        Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
    }
}
}

ที่นี่ถ้าคุณแสดงความคิดเห็นผู้สร้างเริ่มต้นแล้วรหัสจะโยนด้านล่างยกเว้น:

 java.io.InvalidClassException: javaserialization.MyExternalizable;     
 javaserialization.MyExternalizable; no valid constructor.

เราสามารถสังเกตได้ว่าเนื่องจากรหัสผ่านเป็นข้อมูลที่ละเอียดอ่อนดังนั้นฉันจึงไม่เป็นอนุกรมในวิธีการ writeExternal (ObjectOutput oo) และไม่ได้ตั้งค่าเหมือนกันใน readExternal (ObjectInput oi) นั่นเป็นความยืดหยุ่นที่จัดทำโดย Externalizable

ผลลัพธ์ของรหัสข้างต้นเป็นดังต่อไปนี้:

userName: nikki  passWord: student001  roll: 20
***********************************************************************
userName: nikki  passWord: null  roll: 20

เราสามารถสังเกตได้เนื่องจากเราไม่ได้ตั้งค่าของรหัสผ่านดังนั้นมันจึงเป็นโมฆะ

สามารถทำได้เช่นเดียวกันโดยการประกาศฟิลด์รหัสผ่านเป็นชั่วคราว

private transient String passWord;

หวังว่ามันจะช่วย ฉันขอโทษถ้าฉันทำผิดพลาด ขอบคุณ


22

ความแตกต่างที่สำคัญระหว่างSerializableและExternalizable

  1. เครื่องหมายส่วนต่อประสาน : Serializableเป็นส่วนต่อประสานเครื่องหมายโดยไม่ใช้วิธีการใด ๆ Externalizableอินเตอร์เฟซที่มีสองวิธี: และwriteExternal()readExternal()
  2. กระบวนการทำให้เป็นอนุกรม : กระบวนการทำให้เป็นอนุกรมเริ่มต้นจะถูกเตะเข้าสำหรับชั้นเรียนที่ใช้Serializableส่วนต่อประสาน กระบวนการ Serialization ที่โปรแกรมเมอร์กำหนดจะถูกเตะเข้าสำหรับคลาสที่ใช้Externalizableอินเตอร์เฟส
  3. การบำรุงรักษา : การเปลี่ยนแปลงที่เข้ากันไม่ได้อาจทำลายการทำให้เป็นอนุกรม
  4. ความเข้ากันได้และการควบคุมย้อนหลัง : หากคุณต้องรองรับหลาย ๆ เวอร์ชันคุณสามารถควบคุมได้อย่างสมบูรณ์ด้วยExternalizableส่วนต่อประสาน คุณสามารถรองรับวัตถุรุ่นต่าง ๆ ของคุณ หากคุณใช้งานExternalizableเป็นความรับผิดชอบของคุณในการทำให้superคลาสเป็นอนุกรม
  5. public No-arg ตัวสร้าง : Serializableใช้การสะท้อนเพื่อสร้างวัตถุและไม่ต้องการตัวสร้าง arg แต่Externalizableต้องการตัวสร้างแบบไม่มีอาร์กิวเมนต์สาธารณะ

อ้างถึงบล็อกโดยHitesh Gargสำหรับรายละเอียดเพิ่มเติม


1
(3) ไม่ถูกต้อง มีการเปลี่ยนแปลงขนาดใหญ่ที่คุณสามารถทำกับคลาสได้โดยไม่ทำให้วัตถุที่มีอยู่ต่อเนื่องเสื่อมสภาพและการเพิ่มสมาชิก serializable เป็นหนึ่งในนั้น การลบมันเป็นอีกเรื่องหนึ่ง ดูที่บทการกำหนดเวอร์ชันวัตถุของข้อกำหนดคุณสมบัติการทำให้เป็นอันดับของวัตถุ
มาร์ควิสแห่ง Lorne

1
เขียนประโยคอีกประโยค
Ravindra babu

ขอบคุณสำหรับการแชร์ลิงก์ไปยังข้อมูลจำเพาะการทำให้เป็นอันดับ
JL_SO

21

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

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


5
เราใช้ Externalizable สำหรับคอลเลกชันขนาดใหญ่ของ "รหัสที่เลือก" - มันเป็นสิ่งที่มีประสิทธิภาพมากกว่าการทำ externalizing เมื่อนับจำนวนมาก & อาร์เรย์ของ int ดั้งเดิมแทนที่จะเป็นอนุกรมเริ่มต้น นั่นเป็น usecase ที่ง่ายมากไม่มีอะไรที่ "พิเศษ" หรือ "ไม่เหมือนใคร"
โทมัส W

9

การทำให้เป็นอันดับวัตถุใช้อินเทอร์เฟซแบบอนุกรมและ Externalizable วัตถุ Java จะต่อเนื่องได้เท่านั้น ถ้าคลาสหรือซูเปอร์คลาสใด ๆ ของมันใช้ส่วนต่อประสาน java.io.Serializable หรือ subinterface, java.io.Externalizable คลาสจาวาส่วนใหญ่สามารถต่ออนุกรมได้

  • NotSerializableException: packageName.ClassName«ในการเข้าร่วม Class Object ในกระบวนการทำให้เป็นอนุกรมคลาสจะต้องใช้อินเตอร์เฟสที่ปรับให้เป็นแบบอนุกรมหรือแบบถอดได้

ป้อนคำอธิบายรูปภาพที่นี่


อินเตอร์เฟสแบบอนุกรม

การทำให้เป็นอันดับวัตถุจะสร้างสตรีมที่มีข้อมูลเกี่ยวกับคลาส Java สำหรับวัตถุที่กำลังถูกบันทึก สำหรับออบเจ็กต์ที่ทำให้เป็นอนุกรมข้อมูลที่เพียงพอจะถูกเก็บไว้เพื่อกู้คืนออบเจ็กต์เหล่านั้นแม้ว่าจะมีเวอร์ชันที่แตกต่างกัน อินเตอร์เฟส Serializable ถูกกำหนดเพื่อระบุคลาสที่ใช้โปรโตคอล serializable:

package java.io;

public interface Serializable {};
  • อินเตอร์เฟสการทำให้เป็นอนุกรมไม่มีเมธอดหรือฟิลด์และทำหน้าที่เพื่อระบุความหมายของการทำให้เป็นอนุกรมเท่านั้น สำหรับ serializing / deserializing คลาสเราสามารถใช้เมธอด writeObject และ readObject เริ่มต้น (หรือ) เราสามารถแทนที่เมธอด writeObject และ readObject จากคลาส
  • JVM จะมีการควบคุมที่สมบูรณ์ในการทำให้วัตถุเป็นอนุกรม ใช้คำหลักชั่วคราวเพื่อป้องกันไม่ให้สมาชิกข้อมูลถูกทำให้เป็นอนุกรม
  • ที่นี่วัตถุที่ต่อเนื่องกันได้จะถูกสร้างขึ้นใหม่โดยตรงจากกระแสโดยไม่ต้องดำเนินการ
  • InvalidClassException«ในกระบวนการดีซีเรียลไลเซชันถ้าค่าคลาสlocalVersionUIDแตกต่างจากคลาสของผู้ส่งที่สอดคล้องกัน จากนั้นผลลัพธ์จะขัดแย้งกันดังนี้ java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
  • ค่าของเขตข้อมูลที่ไม่ใช่แบบชั่วคราวและแบบไม่คงที่ของคลาสจะถูกทำให้เป็นอนุกรม

อินเตอร์เฟสภายนอก

สำหรับวัตถุที่ปรับขนาดได้จะมีการบันทึกตัวตนของคลาสของวัตถุเท่านั้นโดยคอนเทนเนอร์ ชั้นจะต้องบันทึกและกู้คืนเนื้อหา อินเตอร์เฟส Externalizable ถูกกำหนดดังนี้:

package java.io;

public interface Externalizable extends Serializable
{
    public void writeExternal(ObjectOutput out)
        throws IOException;

    public void readExternal(ObjectInput in)
        throws IOException, java.lang.ClassNotFoundException;
}
  • อินเทอร์เฟซที่ใช้การได้มีสองวิธีออบเจกต์ที่ปรับขนาดได้จะต้องใช้เมธอด writeExternal และ readExternal เพื่อบันทึก / กู้คืนสถานะของวัตถุ
  • โปรแกรมเมอร์ต้องดูแลวัตถุที่จะถูกทำให้เป็นอนุกรม ในฐานะโปรแกรมเมอร์ดูแล Serialization ดังนั้นที่นี่คำหลักชั่วคราวจะไม่ จำกัด วัตถุใด ๆ ในกระบวนการเป็นอันดับ
  • เมื่อวัตถุภายนอกได้ถูกสร้างขึ้นใหม่อินสแตนซ์จะถูกสร้างขึ้นโดยใช้คอนสตรัคเตอร์ no-arg สาธารณะจากนั้นจะเรียกใช้เมธอด readExternal วัตถุที่ทำให้เป็นอนุกรมได้รับการกู้คืนโดยการอ่านจาก ObjectInputStream
  • OptionalDataException«เขตข้อมูลต้องอยู่ในลำดับและประเภทเดียวกันขณะที่เราเขียนออกมา หากมีชนิดไม่ตรงกันใด ๆ จากสตรีมจะมีการระบุตัวเลือก DataException

    @Override public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt( id );
        out.writeUTF( role );
        out.writeObject(address);
    }
    @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.id = in.readInt();
        this.address = (Address) in.readObject();
        this.role = in.readUTF();
    }
  • เขตข้อมูลอินสแตนซ์ของคลาสที่เขียน(เปิดเผย)เพื่อObjectOutputรับอนุกรม


ตัวอย่าง«ใช้ Serializable

class Role {
    String role;
}
class User extends Role implements Serializable {

    private static final long serialVersionUID = 5081877L;
    Integer id;
    Address address;

    public User() {
        System.out.println("Default Constructor get executed.");
    }
    public User( String role ) {
        this.role = role;
        System.out.println("Parametarised Constructor.");
    }
}

class Address implements Serializable {

    private static final long serialVersionUID = 5081877L;
    String country;
}

ตัวอย่าง«ใช้ Externalizable

class User extends Role implements Externalizable {

    Integer id;
    Address address;
    // mandatory public no-arg constructor
    public User() {
        System.out.println("Default Constructor get executed.");
    }
    public User( String role ) {
        this.role = role;
        System.out.println("Parametarised Constructor.");
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt( id );
        out.writeUTF( role );
        out.writeObject(address);
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.id = in.readInt();
        this.address = (Address) in.readObject();
        this.role = in.readUTF();
    }
}

ตัวอย่าง

public class CustomClass_Serialization {
    static String serFilename = "D:/serializable_CustomClass.ser";

    public static void main(String[] args) throws IOException {
        Address add = new Address();
        add.country = "IND";

        User obj = new User("SE");
        obj.id = 7;
        obj.address = add;

        // Serialization
        objects_serialize(obj, serFilename);
        objects_deserialize(obj, serFilename);

        // Externalization
        objects_WriteRead_External(obj, serFilename);
    }

    public static void objects_serialize( User obj, String serFilename ) throws IOException{
        FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );

        // java.io.NotSerializableException: com.github.objects.Address
        objectOut.writeObject( obj );
        objectOut.flush();
        objectOut.close();
        fos.close();

        System.out.println("Data Stored in to a file");
    }
    public static void objects_deserialize( User obj, String serFilename ) throws IOException{
        try {
            FileInputStream fis = new FileInputStream( new File( serFilename ) );
            ObjectInputStream ois = new ObjectInputStream( fis );
            Object readObject;
            readObject = ois.readObject();
            String calssName = readObject.getClass().getName();
            System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException

            User user = (User) readObject;
            System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);

            Address add = (Address) user.address;
            System.out.println("Inner Obj : "+ add.country );
            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void objects_WriteRead_External( User obj, String serFilename ) throws IOException {
        FileOutputStream fos = new FileOutputStream(new File( serFilename ));
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );

        obj.writeExternal( objectOut );
        objectOut.flush();

        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            // create a new instance and read the assign the contents from stream.
            User user = new User();

            FileInputStream fis = new FileInputStream(new File( serFilename ));
            ObjectInputStream ois = new ObjectInputStream( fis );

            user.readExternal(ois);

            System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);

            Address add = (Address) user.address;
            System.out.println("Inner Obj : "+ add.country );
            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

@ดู


7

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

ตัวอย่างของการดำเนินการนี้คือการใช้งานของระยะไกล AMF (รูปแบบข้อความ ActionScript) เพื่อถ่ายโอนวัตถุสคริปต์การกระทำดั้งเดิมผ่านเครือข่าย


7

https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html

เริ่มต้นการทำให้เป็นอนุกรมค่อนข้าง verbose และสมมติสถานการณ์การใช้งานที่เป็นไปได้ที่กว้างที่สุดของวัตถุที่เป็นอนุกรมและตามรูปแบบเริ่มต้น (Serializable) บันทึกย่อกระแสข้อมูลผลลัพธ์กับข้อมูลเกี่ยวกับชั้นของวัตถุที่ทำให้เป็นอันดับ

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

นอกจากนี้การส่งออก (ตามที่ระบุ Uri) ยังมีการควบคุมการเข้ารหัสข้อมูลในสตรีมที่สอดคล้องกับประเภท Java อย่างสมบูรณ์ สำหรับตัวอย่าง (ที่วางแผนไว้) คุณอาจต้องการบันทึกบูลีนจริงเช่น 'Y' และเท็จเป็น 'N' Externalization ช่วยให้คุณทำเช่นนั้นได้


2

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


2

มีความแตกต่างมากมายระหว่าง Serializable และ Externalable แต่เมื่อเราเปรียบเทียบความแตกต่างระหว่าง Customizable (แทนที่ writeObject () & readObject ()) และ Externalizable จากนั้นเราพบว่าการใช้งานที่กำหนดเองถูกผูกไว้อย่างแน่นหนากับคลาส ObjectOutputStream จัดเตรียมการประยุกต์ใช้ ObjectOutput ซึ่งอาจเป็นคลาส ObjectOutputStream หรืออาจเป็นอย่างอื่นเช่น org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream

ในกรณีที่อินเตอร์เฟสภายนอก

@Override
public void writeExternal(ObjectOutput out) throws IOException {
    out.writeUTF(key);
    out.writeUTF(value);
    out.writeObject(emp);
}

@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    this.key = in.readUTF();
    this.value = in.readUTF();
    this.emp = (Employee) in.readObject();
}





**In case of Serializable interface**


        /* 
             We can comment below two method and use default serialization process as well
             Sequence of class attributes in read and write methods MUST BE same.
        // below will not work it will not work . 
        // Exception = java.io.StreamCorruptedException: invalid type code: 00\
              private void writeObject(java.io.ObjectOutput stream) 
              */
            private void writeObject(java.io.ObjectOutputStream Outstream)
                    throws IOException {

                System.out.println("from writeObject()");
                /*     We can define custom validation or business rules inside read/write methods.
 This way our validation methods will be automatically 
    called by JVM, immediately after default serialization 
    and deserialization process 
    happens.
                 checkTestInfo();
                */

                stream.writeUTF(name);
                stream.writeInt(age);
                stream.writeObject(salary);
                stream.writeObject(address);
            }

            private void readObject(java.io.ObjectInputStream Instream)
                    throws IOException, ClassNotFoundException {
                System.out.println("from readObject()");
                name = (String) stream.readUTF();
                age = stream.readInt();
                salary = (BigDecimal) stream.readObject();
                address = (Address) stream.readObject();
                // validateTestInfo();
            }

ฉันได้เพิ่มโค้ดตัวอย่างเพื่ออธิบายให้ดีขึ้น โปรดตรวจสอบกรณีวัตถุเข้า / ออกของ Externalable สิ่งเหล่านี้ไม่ได้ผูกพันกับการนำไปใช้โดยตรง
โดยที่ Outstream / Instream ผูกเข้ากับคลาสอย่างแน่นหนา เราสามารถขยาย ObjectOutputStream / ObjectInputStream แต่มันจะยากที่จะใช้


1
คุณช่วยอธิบายเพิ่มเติมได้ไหม? ขณะที่ฉันอ่านฉันไม่เข้าใจสิ่งที่คุณกำลังพยายามจะพูด นอกจากนี้หากคุณสามารถจัดรูปแบบข้อความด้วยย่อหน้าและตัวอย่างบางส่วนนี่อาจเป็นคำตอบที่ดี
Shirkam

0

โดยพื้นฐานแล้วSerializableอินเตอร์เฟสของตัวทำเครื่องหมายที่บอกเป็นนัยว่าคลาสนั้นปลอดภัยสำหรับการทำให้เป็นอนุกรมและ JVM กำหนดวิธีที่จะทำให้เป็นอนุกรม Externalizableมี 2 วิธีการและreadExternal อนุญาตให้ผู้ใช้ทำการตัดสินใจว่าวัตถุนั้นถูกทำให้เป็นอนุกรมอย่างไร, ในฐานะที่วัตถุเป็นอนุกรมวิธีที่เป็นค่าเริ่มต้นwriteExternalExternalizableSerializable


0

ความแตกต่างบางประการ:

  1. สำหรับการทำให้เป็นอนุกรมไม่จำเป็นต้องมีคอนสตรัคเตอร์เริ่มต้นของคลาสนั้นเนื่องจาก Object เนื่องจาก JVM สร้างสิ่งเดียวกันด้วยความช่วยเหลือของ Reflection API ในกรณีที่มีสิ่งก่อสร้างภายนอกที่ไม่ต้องการอาร์คเนื่องจากตัวควบคุมอยู่ในมือของโปรแกรมและหลังจากนั้นกำหนดข้อมูลที่ดีซีเรียลไลซ์ให้กับวัตถุผ่านตัวตั้งค่า

  2. ในการทำให้เป็นอนุกรมหากผู้ใช้ต้องการข้ามคุณสมบัติบางอย่างที่จะทำให้เป็นอนุกรมนั้นจะต้องทำเครื่องหมายคุณสมบัตินั้นว่าเป็นแบบชั่วคราวไม่จำเป็นต้องใช้ในทางกลับกัน

  3. เมื่อคาดว่าจะรองรับการรองรับความเข้ากันได้แบบย้อนหลังสำหรับคลาสใดก็ตามแนะนำให้ใช้กับ Externalizable การทำให้เป็นอนุกรมรองรับ defaultObject persisting และถ้าโครงสร้างของวัตถุแตกแล้วมันจะทำให้เกิดปัญหาขณะ deserializing

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.