Apa perbedaan antara Serializable dan Externalizable di Jawa?

Jawaban:

267

Untuk menambah jawaban lain, dengan mengimplementasikan java.io.Serializable, Anda mendapatkan kemampuan serialisasi "otomatis" untuk objek kelas Anda. Tidak perlu menerapkan logika lain, itu hanya akan berfungsi. Java runtime akan menggunakan refleksi untuk mengetahui cara menyusun dan menghapus objek Anda.

Dalam versi Java yang lebih lama, refleksi sangat lambat, dan karenanya serializaing grafik objek besar (misalnya dalam aplikasi RMI client-server) adalah sedikit masalah kinerja. Untuk menangani situasi ini, java.io.Externalizableantarmuka disediakan, yang seperti java.io.Serializabletetapi dengan mekanisme yang dibuat khusus untuk melakukan fungsi marshalling dan unmarshalling (Anda perlu mengimplementasikan readExternaldan writeExternalmetode pada kelas Anda). Ini memberi Anda sarana untuk mengatasi hambatan kinerja refleksi.

Dalam versi Jawa terbaru (1.3 dan seterusnya, tentu saja) kinerja refleksi jauh lebih baik daripada sebelumnya, dan ini jauh lebih sedikit masalah. Saya curiga Anda akan kesulitan untuk mendapatkan manfaat yang berarti dari ExternalizableJVM modern.

Juga, mekanisme serialisasi Java bawaan bukan satu-satunya, Anda bisa mendapatkan penggantian pihak ketiga, seperti JBoss Serialization, yang jauh lebih cepat, dan merupakan pengganti drop-in untuk default.

Kelemahan besar Externalizableadalah Anda harus mempertahankan logika ini sendiri - jika Anda menambah, menghapus, atau mengubah bidang di kelas Anda, Anda harus mengubah metode writeExternal/ Anda readExternaluntuk menjelaskannya.

Singkatnya, Externalizableadalah peninggalan dari Jawa 1,1 hari. Benar-benar tidak perlu lagi.

skaffman
sumber
61
Tidak sesuai dengan tolok ukur ini: [ code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking] , serialisasi manual (menggunakan eksternalisasi) jauh, jauh lebih cepat daripada menggunakan serialisasi default java. Jika kecepatan penting untuk pekerjaan Anda, pasti tulis serializer Anda sendiri.
volni
6
memperbarui ke tautan baru github.com/eishay/jvm-serializers/wiki yang disarankan oleh @Jack
noquery
3
"Java-manual" di github.com/eishay/jvm-serializers/wiki tidak tidak menggunakan Externalizable, yang akan berarti menggunakan ObjectOutputStream. Lihat github.com/eishay/jvm-serializers/wiki/ToolBehavior untuk tautan ke kode. Sebaliknya, ini adalah kode tulisan tangan yang menggunakan DataOutputStream, sehingga tidak mengalami hal-hal yang membuat ObjectOutputStream lambat (seperti melacak instance objek dan siklus objek pendukung).
Esko Luontola
7
Harus mempertahankan logika sendiri hanyalah kerugian jika kelas tidak pernah berubah dan Anda tidak perlu membaca versi lama dari data lama. Jika Anda ingin kebebasan untuk mengubah kelas Anda tanpa harus menulis kode neraka untuk deserialize versi lama itu, Externalizablemembantu banyak .
Tim Boudreau
2
Saya hanya perlu menulis koleksi khusus dan saya harus mengatakan itu Externalizablecocok untuk saya jauh lebih baik, karena saya tidak ingin menampilkan array dengan ruang kosong atau objek placeholder, ditambah dengan antarmuka eksplisit Anda dapat menangani warisan, yang berarti sub tersinkronisasi saya -kelas dapat dengan mudah menambahkan mengunci di sekitar panggilan writeExternal(). Jadi ya, Externalizable masih sangat relevan, tentunya untuk objek besar atau kompleks.
Haravikk
37

Serialisasi memberikan fungsionalitas default untuk menyimpan dan kemudian membuat ulang objek. Menggunakan format verbose untuk mendefinisikan seluruh grafik objek yang akan disimpan misalkan Anda memiliki linkedList dan kode Anda seperti di bawah ini, maka serialisasi default akan menemukan semua objek yang terhubung dan akan bersambung. Dalam serialisasi default, objek dibangun sepenuhnya dari bit yang tersimpan, tanpa panggilan konstruktor.

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

Tetapi jika Anda ingin serialisasi terbatas atau tidak ingin sebagian dari objek Anda menjadi serial, gunakan Externalizable. Antarmuka Externalizable memperluas antarmuka Serializable dan menambahkan dua metode, writeExternal () dan readExternal (). Ini secara otomatis disebut serialisasi atau deserialization. Ketika bekerja dengan Externalizable kita harus ingat bahwa konstructer default harus publik atau kode akan membuang pengecualian. Silakan ikuti kode di bawah ini:

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

Di sini jika Anda mengomentari konstruktor default, maka kode tersebut akan membuang pengecualian di bawah ini:

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

Kita dapat mengamati bahwa kata sandi adalah informasi sensitif, jadi saya tidak membuat serialisasi dalam metode writeExternal (ObjectOutput oo) dan tidak menetapkan nilai yang sama di readExternal (ObjectInput oi). Itulah fleksibilitas yang disediakan oleh Externalizable.

Output dari kode di atas adalah seperti di bawah ini:

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

Kita dapat mengamati karena kita tidak menetapkan nilai passWord jadi nol.

Hal yang sama juga dapat dicapai dengan mendeklarasikan bidang kata sandi sebagai sementara.

private transient String passWord;

Semoga ini bisa membantu. Saya minta maaf jika saya melakukan kesalahan. Terima kasih.

Mencoba
sumber
22

Perbedaan utama antara SerializabledanExternalizable

  1. Antarmuka penanda : Serializableadalah antarmuka penanda tanpa metode apa pun. Externalizableantarmuka berisi dua metode: writeExternal()dan readExternal().
  2. Proses serialisasi : Proses serialisasi default akan dimulai untuk Serializableantarmuka yang mengimplementasikan kelas . Programer mendefinisikan proses Serialisasi akan ditendang untuk kelas yang mengimplementasikan Externalizableantarmuka.
  3. Pemeliharaan : Perubahan yang tidak kompatibel dapat merusak serialisasi.
  4. Kompatibilitas dan Kontrol Mundur : Jika Anda harus mendukung banyak versi, Anda dapat memiliki kontrol penuh dengan Externalizableantarmuka. Anda dapat mendukung berbagai versi objek Anda. Jika Anda menerapkan Externalizable, Anda bertanggung jawab untuk membuat cerita bersambung superkelas
  5. public No-arg constructor : Serializablemenggunakan refleksi untuk membangun objek dan tidak memerlukan konstruktor arg. Tetapi Externalizablemenuntut konstruktor tanpa argumen publik.

Rujuk ke blog dengan Hitesh Garguntuk lebih jelasnya.

Ravindra babu
sumber
1
(3) salah. Ada repertoar besar perubahan yang dapat Anda buat ke kelas tanpa melanggar de-serialisasi objek yang ada, dan menambahkan anggota yang dapat serial tentu merupakan salah satunya. Menghapusnya adalah hal lain. Lihat bab Pembuatan Versi Objek dari Spesifikasi Serialisasi Objek Java.
Marquis of Lorne
1
Kalimat ulang.
Ravindra babu
Terima kasih telah berbagi tautan ke spesifikasi Serialisasi.
JL_SO
21

Serialisasi menggunakan perilaku default tertentu untuk menyimpan dan kemudian membuat ulang objek. Anda dapat menentukan dalam urutan apa atau bagaimana menangani referensi dan struktur data yang kompleks, tetapi pada akhirnya bermuara pada penggunaan perilaku default untuk setiap bidang data primitif.

Eksternalisasi digunakan dalam kasus langka yang Anda benar-benar ingin menyimpan dan membangun kembali objek Anda dengan cara yang sama sekali berbeda dan tanpa menggunakan mekanisme serialisasi default untuk bidang data. Misalnya, bayangkan Anda memiliki skema penyandian dan kompresi unik Anda sendiri.

Uri
sumber
5
Kami menggunakan Externalizable untuk koleksi besar "ID yang dipilih" - itu jauh lebih efisien eksternalisasi sebagai lebih & kurang hitungan & array int primitif, daripada serialisasi default. Itu usecase yang sangat sederhana, tidak ada yang "istimewa" atau "unik".
Thomas W
9

Obyek Serialization menggunakan antarmuka Serializable dan Externalizable. Objek Java hanya bisa serial. jika suatu kelas atau salah satu dari superclasses mengimplementasikan antarmuka java.io.Serializable atau subinterface-nya, java.io.Externalizable. Sebagian besar kelas java serializable .

  • NotSerializableException: packageName.ClassName«Untuk berpartisipasi dalam Obyek Kelas dalam proses serialisasi, kelas harus mengimplementasikan antarmuka Serializable atau Eksternalisasi.

masukkan deskripsi gambar di sini


Antarmuka Serializable

Serialisasi objek menghasilkan aliran dengan informasi tentang kelas Java untuk objek yang disimpan. Untuk objek serializable, informasi yang cukup disimpan untuk mengembalikan objek-objek itu bahkan jika versi implementasi kelas yang berbeda (namun kompatibel) ada. Antarmuka Serializable didefinisikan untuk mengidentifikasi kelas yang mengimplementasikan protokol serializable:

package java.io;

public interface Serializable {};
  • Antarmuka serialisasi tidak memiliki metode atau bidang dan hanya berfungsi untuk mengidentifikasi semantik menjadi serial. Untuk membuat serial / deserializing suatu kelas, kita dapat menggunakan metode writeObject dan readObject default (atau) kita dapat mengganti metode writeObject dan readObject dari sebuah kelas.
  • JVM akan memiliki kontrol penuh dalam membuat serialisasi objek. menggunakan kata kunci sementara untuk mencegah anggota data dari serial.
  • Di sini objek serializable direkonstruksi langsung dari aliran tanpa mengeksekusi
  • InvalidClassException«Dalam proses deserialisasi, jika nilai serialVersionUID kelas lokal berbeda dari kelas pengirim yang bersangkutan. kemudian berakibat konflik sebagai java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
  • Nilai-nilai bidang non-transient dan non-statis kelas mendapatkan serial.

Antarmuka Eksternalisasi

Untuk objek yang dapat dieksternalisasi, hanya identitas kelas objek yang disimpan oleh wadah; kelas harus menyimpan dan mengembalikan konten. Antarmuka yang Eksternalisasi didefinisikan sebagai berikut:

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;
}
  • Antarmuka Externalizable memiliki dua metode, objek yang dieksternalisasi harus menerapkan metode writeExternal dan readExternal untuk menyimpan / mengembalikan keadaan objek.
  • Programmer harus mengurus objek yang akan di-serial. Sebagai seorang programmer yang menangani Serialisasi, maka kata kunci sementara tidak akan membatasi objek apa pun dalam proses Serialisasi.
  • Ketika objek Externalizable direkonstruksi, sebuah instance dibuat menggunakan konstruktor no-arg publik, kemudian metode readExternal dipanggil. Objek berseri dipulihkan dengan membacanya dari ObjectInputStream.
  • OptionalDataException«Kolom HARUS DALAM PESANAN DAN TIPE YANG SAMA saat kami menuliskannya. Jika ada ketidakcocokan jenis dari aliran itu melempar OptionalDataException.

    @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();
    }
  • Bidang instance kelas yang ditulis (terbuka) untuk ObjectOutputmendapatkan serial.


Contoh « mengimplementasikan 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;
}

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

Contoh

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

@Lihat

Yash
sumber
7

Antarmuka yang Eksternalisasi sebenarnya tidak disediakan untuk mengoptimalkan kinerja proses serialisasi! tetapi untuk menyediakan cara menerapkan pemrosesan kustom Anda sendiri dan menawarkan kontrol penuh atas format dan konten aliran untuk objek dan tipe supernya!

Contohnya adalah penerapan remoting AMF (ActionScript Message Format) untuk mentransfer objek skrip aksi asli melalui jaringan.

Ali Joudeh
sumber
7

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

Serialisasi default agak bertele-tele, dan mengasumsikan skenario penggunaan seluas mungkin dari objek berseri, dan karenanya format default (Serializable) menjelaskan aliran yang dihasilkan dengan informasi tentang kelas objek berseri.

Eksternalisasi memberi produsen aliran objek kontrol penuh atas meta-data kelas yang tepat (jika ada) di luar identifikasi kelas yang minimal diperlukan (misalnya namanya). Ini jelas diinginkan dalam situasi tertentu, seperti lingkungan tertutup, di mana produsen aliran objek dan penggunanya (yang mengubah objek dari aliran) dicocokkan, dan metadata tambahan tentang kelas tidak memiliki tujuan dan menurunkan kinerja.

Selain itu (seperti yang ditunjukkan oleh Uri) eksternalisasi juga menyediakan kontrol penuh atas penyandian data dalam aliran yang sesuai dengan tipe Java. Sebagai contoh (dibuat-buat), Anda mungkin ingin merekam boolean true sebagai 'Y' dan false sebagai 'N'. Eksternalisasi memungkinkan Anda melakukan itu.

alphazero
sumber
2

Saat mempertimbangkan opsi untuk meningkatkan kinerja, jangan lupa serialisasi khusus. Anda dapat membiarkan Java melakukan apa yang dilakukannya dengan baik, atau setidaknya cukup baik, gratis , dan memberikan dukungan khusus untuk apa yang dilakukannya dengan buruk. Ini biasanya jauh lebih sedikit kode daripada dukungan penuh eksternalisasi.

Ed Staub
sumber
2

Ada begitu banyak perbedaan yang ada antara Serializable dan Externalizable tetapi ketika kita membandingkan perbedaan antara custom Serializable (override writeObject () & readObject ()) dan Externalizable maka kita menemukan bahwa implementasi custom terikat erat dengan kelas ObjectOutputStream di mana seperti dalam kasus Externalizable, kita sendiri menyediakan implementasi ObjectOutput yang mungkin kelas ObjectOutputStream atau bisa juga yang lain seperti org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream

Dalam hal antarmuka Externalizable

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

Saya telah menambahkan kode sampel untuk menjelaskan lebih baik. silakan periksa objek objek Externalizable. Ini tidak terikat dengan implementasi apa pun secara langsung.
Sedangkan Outstream / Instream mengikat erat ke kelas. Kita dapat memperluas ObjectOutputStream / ObjectInputStream tetapi akan sedikit sulit untuk digunakan.

Ashish Sharma
sumber
1
Bisakah Anda menjelaskannya lebih lanjut? Ketika saya membacanya, saya tidak mengerti apa yang ingin Anda katakan. Juga, jika Anda bisa memformat teks dengan beberapa paragraf dan contoh, ini bisa menjadi jawaban yang bagus.
Shirkam
0

Pada dasarnya, Serializableadalah antarmuka penanda yang menyiratkan bahwa suatu kelas aman untuk serialisasi dan JVM menentukan bagaimana itu serial. Externalizableberisi 2 metode, readExternaldan writeExternal. Externalizablememungkinkan pelaksana untuk memutuskan bagaimana suatu objek diserialisasi, Serializablesedangkan serialisasi objek dengan cara default.

Pika sang Penyihir Paus
sumber
0

Beberapa perbedaan:

  1. Untuk Serialisasi tidak diperlukan konstruktor default kelas itu karena Objek karena JVM membangun yang sama dengan bantuan API Refleksi. Dalam kasus kontruktor Eksternalisasi tanpa arg diperlukan, karena kontrol ada di tangan program dan kemudian menetapkan data deserialized ke objek melalui setter.

  2. Dalam serialisasi jika pengguna ingin melewatkan properti tertentu untuk diserialisasi maka harus menandai properti itu sebagai sementara, sebaliknya tidak diperlukan untuk Eksternalisasi.

  3. Ketika dukungan kompatibilitas mundur diharapkan untuk kelas apa pun maka disarankan untuk pergi dengan Externalizable. Serialisasi mendukung defaultObject bertahan dan jika struktur objek rusak maka akan menyebabkan masalah saat deserializing.

Neeraj
sumber