it-swarm.com.de

Was ist der Unterschied zwischen serialisierbar und externalisierbar in Java?

Was ist der Unterschied zwischen Serializable und Externalizable in Java?

268
Sasha

Um andere Antworten hinzuzufügen, erhalten Sie durch die Implementierung von Java.io.Serializable "automatische" Serialisierungsfunktionen für Objekte Ihrer Klasse. Sie müssen keine andere Logik implementieren, es funktioniert einfach. Die Java-Laufzeitumgebung verwendet Reflection, um herauszufinden, wie Sie Objekte deklarieren und dekomprimieren.

In früheren Java-Versionen war die Reflexion sehr langsam, weshalb das Serialisieren großer Objektdiagramme (z. B. in Client-Server-RMI-Anwendungen) ein Leistungsproblem war. Um dieser Situation zu begegnen, wurde die Java.io.Externalizable-Schnittstelle bereitgestellt, die wie Java.io.Serializable aussieht, jedoch mit benutzerdefinierten Mechanismen zum Ausführen der Marshalling- und Unmarshalling-Funktionen (Sie müssen readExternal- und writeExternal-Methoden in Ihrer Klasse implementieren). Dies gibt Ihnen die Mittel, um den Engpass bei der Reflexionsleistung zu umgehen. 

In den jüngsten Versionen von Java (ab Version 1.3) ist die Reflexionsleistung jetzt deutlich besser als früher, sodass dies ein viel geringeres Problem darstellt. Ich vermute, Sie würden sich schwer tun, mit einer modernen JVM von Externalizable einen sinnvollen Nutzen zu ziehen. 

Außerdem ist der integrierte Java-Serialisierungsmechanismus nicht der einzige. Sie können von Drittanbietern wie JBoss Serialization ersetzt werden, was erheblich schneller ist und ein Drop-In-Ersatz für den Standard ist.

Ein großer Nachteil von Externalizable ist, dass Sie diese Logik selbst pflegen müssen. Wenn Sie ein Feld in Ihrer Klasse hinzufügen, entfernen oder ändern, müssen Sie Ihre writeExternal/readExternal-Methoden ändern, um dies zu berücksichtigen.

Zusammenfassend ist Externalizable ein Relikt der Java 1.1-Tage. Es ist wirklich nicht mehr nötig.

257
skaffman

Die Serialisierung bietet Standardfunktionen zum Speichern und späteren Erstellen des Objekts. Es verwendet ein ausführliches Format, um den gesamten Graphen der zu speichernden Objekte zu definieren, z. Angenommen, Sie haben eine LinkedList und einen Code wie unten beschrieben, dann erkennt die Standardserialisierung alle Objekte, die verknüpft sind, und serialisiert. Bei der Standardserialisierung wird das Objekt vollständig aus seinen gespeicherten Bits ohne Konstruktoraufrufe erstellt.

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

Wenn Sie jedoch eine eingeschränkte Serialisierung wünschen oder nicht möchten, dass ein Teil Ihres Objekts serialisiert wird, verwenden Sie Externalizable. Die Schnittstelle "Externalizable" erweitert die Schnittstelle "Serializable" und fügt zwei Methoden hinzu: writeExternal () und readExternal (). Diese werden automatisch während der Serialisierung oder Deserialisierung aufgerufen. Bei der Arbeit mit Externalizable sollten wir bedenken, dass der Standardkonstruktor öffentlich sein sollte, andernfalls löst der Code eine Ausnahme aus. Bitte folgen Sie dem untenstehenden Code:

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

Wenn Sie hier den Standardkonstruktor kommentieren, wird der Code unter einer Ausnahme ausgelöst:

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

Wir können beobachten, dass das Kennwort vertrauliche Informationen ist. Daher serialisiere ich es nicht in der writeExternal (ObjectOutput oo) -Methode und setze nicht den gleichen Wert in readExternal (ObjectInput oi). Das ist die Flexibilität, die Externalizable bietet. 

Die Ausgabe des obigen Codes ist wie folgt:

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

Wir können beobachten, wie wir den Wert von passWord nicht setzen, also ist es null.

Dasselbe kann auch erreicht werden, indem das Kennwortfeld als vorübergehend definiert wird.

private transient String passWord;

Ich hoffe es hilft. Ich entschuldige mich, wenn ich Fehler gemacht habe. Vielen Dank.

34
Trying

Der Vollständigkeit halber schließt das Schlüsselwort transient auch die Lücke zwischen den beiden. 

Wenn Sie nur einen Teil Ihres Objekts serialisieren möchten, setzen Sie einfach bestimmte Felder als transient, markieren Sie sie als nicht persistent und implementieren Sie Serializable.

24

Hauptunterschiede zwischen Serializable und Externalizable

  1. Marker interface: Serializable ist ein Marker-Interface ohne Methoden. Die Externalizable-Schnittstelle enthält zwei Methoden: writeExternal() und readExternal().
  2. Serialisierungsprozess: Der Standard-Serialisierungsprozess wird für Klassen aktiviert, die die Serializable-Schnittstelle implementieren. Vom Programmierer definierter Serialisierungsprozess wird für Klassen eingeführt, die Externalizable interface implementieren.
  3. Maintenance: Inkompatible Änderungen Die Serialisierung kann unterbrochen werden. 
  4. Rückwärtskompatibilität und -kontrolle: Wenn Sie mehrere Versionen unterstützen müssen, können Sie mit der Externalizable-Schnittstelle volle Kontrolle haben. Sie können verschiedene Versionen Ihres Objekts unterstützen. Wenn Sie Externalizable implementieren, liegt es in Ihrer Verantwortung, die super-Klasse zu serialisieren
  5. public No-Arg-Konstruktor: Serializable verwendet Reflektion zum Erstellen eines Objekts und erfordert keinen Arg-Konstruktor. Externalizable fordert jedoch einen öffentlichen No-Arg-Konstruktor.

Weitere Informationen finden Sie in blog by Hitesh Garg

20
Ravindra babu

Bei der Serialisierung werden bestimmte Standardverhalten verwendet, um das Objekt zu speichern und später erneut zu erstellen. Sie können angeben, in welcher Reihenfolge oder wie mit Referenzen und komplexen Datenstrukturen verfahren werden soll. Letztendlich kommt es jedoch darauf an, das Standardverhalten für jedes primitive Datenfeld zu verwenden.

Die Externalisierung wird in den seltenen Fällen verwendet, in denen Sie Ihr Objekt auf völlig andere Weise speichern und neu erstellen möchten, ohne die Standard-Serialisierungsmechanismen für Datenfelder zu verwenden. Stellen Sie sich zum Beispiel vor, Sie hätten Ihr eigenes einzigartiges Kodierungs- und Komprimierungsschema. 

19
Uri

Object Serialization verwendet die Schnittstellen Serializable und Externalizable. Ein Java-Objekt kann nur serialisiert werden. Wenn eine Klasse oder eine ihrer Oberklassen entweder die Java.io.Serializable-Schnittstelle oder deren Subschnittstelle Java.io.Externalizable implementiert. Die meisten Java-Klassen sind serialisierbar.

  • NotSerializableException : packageName.ClassName «Um ein Klassenobjekt am Serialisierungsprozess zu beteiligen, muss die Klasse entweder eine serialisierbare oder eine externalisierbare Schnittstelle implementieren.

 enter image description here


Serialisierbare Schnittstelle

Die Objektserialisierung erzeugt einen Stream mit Informationen zu den Java-Klassen für die Objekte, die gespeichert werden. Für serialisierbare Objekte werden ausreichende Informationen zur Verfügung gestellt, um diese Objekte auch dann wiederherzustellen, wenn eine andere (aber kompatible) Version der Implementierung der Klasse vorhanden ist. Die serialisierbare Schnittstelle ist definiert, um Klassen zu identifizieren, die das serialisierbare Protokoll implementieren:

package Java.io;

public interface Serializable {};
  • Die Serialisierungsschnittstelle hat keine Methoden oder Felder und dient nur dazu, die Semantik der Serialisierung zu identifizieren. Zum Serialisieren/Deserialisieren einer Klasse können wir entweder die Standardmethoden writeObject und readObject verwenden (oder), um die writeObject- und readObject-Methoden einer Klasse zu überschreiben.
  • JVM hat die vollständige Kontrolle über die Serialisierung des Objekts. Verwenden Sie transientes Schlüsselwort, um zu verhindern, dass das Datenelement serialisiert wird.
  • Hier werden serialisierbare Objekte ohne Ausführung direkt aus dem Stream rekonstruiert 
  • InvalidClassException «Wenn sich die lokale Klasse serialVersionUID im Deserialisierungsprozess von der Klasse des entsprechenden Senders unterscheidet, unterscheidet sich der Wert. dann steht das Ergebnis in Konflikt als Java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
  • Die Werte der nicht transienten und nicht statischen Felder der Klasse werden serialisiert.

Externalisierbare Schnittstelle

Bei Externalisierbaren Objekten wird nur die Identität der Klasse des Objekts vom Container gespeichert. Die Klasse muss den Inhalt speichern und wiederherstellen. Die Externalisierbare Schnittstelle ist wie folgt definiert:

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;
}
  • Die Externalizable-Schnittstelle verfügt über zwei Methoden: Ein externalisierbares Objekt muss die Methoden writeExternal und readExternal implementieren, um den Status eines Objekts zu speichern/wiederherzustellen.
  • Der Programmierer muss darauf achten, welche Objekte serialisiert werden sollen. Da ein Programmierer sich um die Serialisierung kümmert, beschränkt das vorübergehende Schlüsselwort also kein Objekt im Serialisierungsprozess.
  • Wenn ein Externalizable-Objekt rekonstruiert wird, wird eine Instanz mit dem öffentlichen Konstruktor no-arg erstellt, und die readExternal-Methode wird aufgerufen. Serialisierbare Objekte werden durch Lesen aus einem ObjectInputStream wiederhergestellt.
  • OptionalDataException «Die Felder MÜSSEN IN DER GLEICHEN BESTELLUNG UND DEM TYPE SIND, wie wir sie geschrieben haben. Wenn eine Abweichung des Typs aus dem Stream vorliegt, wird die Option OptionalDataException ausgelöst.

    @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();
    }
    
  • Die Instanzfelder der Klasse, die (exponiert) in ObjectOutput geschrieben haben, werden serialisiert.


Beispiel « implementiert 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;
}

Beispiel « implementiert Externalisierbar

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

Beispiel

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

@sehen

8
Yash

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

Die Standardserialisierung ist etwas ausführlich und setzt das weitest mögliche Nutzungsszenario des serialisierten Objekts voraus. Entsprechend kommentiert das Standardformat (Serializable) den resultierenden Stream mit Informationen über die Klasse des serialisierten Objekts.

Durch die Externalisierung erhält der Produzent des Objektstroms eine vollständige Kontrolle über die genauen Metadaten der Klasse (falls vorhanden), die über die erforderliche Mindestidentifizierung der Klasse (z. B. ihren Namen) hinausgehen. Dies ist eindeutig in bestimmten Situationen wünschenswert, beispielsweise in geschlossenen Umgebungen, in denen der Producer des Objektstroms und seines Konsumenten (der das Objekt aus dem Stream erneut anzeigt) abgeglichen werden und zusätzliche Metadaten über die Klasse keinen Zweck haben und die Leistung beeinträchtigen.

Darüber hinaus ermöglicht die Externalisierung (wie Uri darauf hinweist) auch die vollständige Kontrolle über die Codierung der Daten im Stream, die den Java-Typen entsprechen. Für ein (erfundenes) Beispiel möchten Sie boolean true als 'Y' und false als 'N' aufnehmen. Durch Externalisierung können Sie das tun.

7
alphazero

Die Schnittstelle "Externalizable" wurde nicht bereitgestellt, um die Leistung des Serialisierungsprozesses zu optimieren! Sie bieten jedoch die Möglichkeit, Ihre eigene benutzerdefinierte Verarbeitung zu implementieren, und bieten vollständige Kontrolle über das Format und den Inhalt des Streams für ein Objekt und dessen Supertypen!

Beispiele hierfür sind die Implementierung von AMF-Remoting (ActionScript Message Format), um native Aktionsskriptobjekte über das Netzwerk zu übertragen.

7
Ali Joudeh

Es gibt so viele Unterschiede zwischen Serializable und Externalizable, aber wenn wir den Unterschied zwischen benutzerdefiniertem Serializable (überschriebenem writeObject () und readObject ()) und Externalizable vergleichen, dann stellen wir fest, dass die benutzerdefinierte Implementierung eng mit der ObjectOutputStream-Klasse verknüpft ist, während wir uns in Externalizable selbst befinden bieten eine Implementierung von ObjectOutput, die die ObjectOutputStream-Klasse sein kann, oder eine andere wie org.Apache.mina.filter.codec.serialization.ObjectSerializationOutputStream

Bei Externalisierbarer Schnittstelle  

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

Ich habe Beispielcode zur besseren Erklärung hinzugefügt. Bitte überprüfen Sie den Objektfall Externalizable in/out. Diese sind nicht direkt an eine Implementierung gebunden.
Wobei Outstream/Instream eng an Klassen gebunden sind. Wir können ObjectOutputStream/ObjectInputStream erweitern, aber es wird etwas schwieriger zu verwenden.

2
Ashish Sharma

Vergessen Sie bei der Auswahl von Optionen zur Verbesserung der Leistung nicht die benutzerdefinierte Serialisierung. Sie können Java tun, was es gut macht oder zumindest gut genug, kostenlos , und benutzerdefinierte Unterstützung für das bieten, was es schlecht macht. Dies ist normalerweise viel weniger Code als die vollständige Unterstützung von Externalizable.

2
Ed Staub

Grundsätzlich ist Serializable eine Markierungsschnittstelle, die besagt, dass eine Klasse für die Serialisierung sicher ist und die JVM bestimmt, wie sie serialisiert wird. Externalizable enthält 2 Methoden, readExternal und writeExternal. Mit Externalizable kann der Implementierer entscheiden, wie ein Objekt serialisiert wird, während Serializable Objekte standardisiert serialisiert.