Was ist der Unterschied zwischen Serializable
und Externalizable
in Java?
Was ist der Unterschied zwischen Serializable
und Externalizable
in Java?
Antworten:
Um die anderen Antworten zu ergänzen java.io.Serializable
, erhalten Sie durch die Implementierung eine "automatische" Serialisierungsfunktion für Objekte Ihrer Klasse. Sie müssen keine andere Logik implementieren, es funktioniert einfach. Die Java-Laufzeit verwendet Reflection, um herauszufinden, wie Sie Ihre Objekte ein- und ausmarschieren können.
In früheren Versionen von Java war die Reflexion sehr langsam, und daher war das Serialisieren großer Objektdiagramme (z. B. in Client-Server-RMI-Anwendungen) ein kleines Leistungsproblem. Um diese Situation zu bewältigen, wurde die java.io.Externalizable
Schnittstelle bereitgestellt, die java.io.Serializable
mit benutzerdefinierten Mechanismen ausgestattet ist, um die Marshalling- und Unmarshalling-Funktionen auszuführen (Sie müssen readExternal
und writeExternal
Methoden für Ihre Klasse implementieren ). Dies gibt Ihnen die Möglichkeit, den Engpass bei der Reflexionsleistung zu umgehen.
In neueren Versionen von Java (sicherlich ab 1.3) ist die Reflexionsleistung erheblich besser als früher, und dies ist daher weitaus weniger problematisch. Ich vermute, es würde Ihnen schwer fallen, Externalizable
mit einer modernen JVM einen sinnvollen Nutzen daraus zu ziehen.
Außerdem ist der integrierte Java-Serialisierungsmechanismus nicht der einzige. Sie können Ersatz von Drittanbietern erhalten, z. B. die JBoss-Serialisierung, die erheblich schneller ist und als Ersatz für die Standardeinstellung dient.
Ein großer Nachteil Externalizable
ist, dass Sie diese Logik selbst beibehalten 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 Externalizable
ist ein Relikt der Java 1.1 Tage. Es ist wirklich nicht mehr nötig.
Externalizable
hilft dies sehr .
Externalizable
viel besser zu mir passt, da ich keine Arrays mit leeren Leerzeichen oder Platzhalterobjekten ausgeben möchte und mit der expliziten Schnittstelle, die Sie für die Vererbung verwenden können, was mein synchronisiertes Sub bedeutet -Klasse kann leicht Sperren um den Anruf hinzufügen writeExternal()
. Also ja, Externalizable ist immer noch sehr relevant, sicherlich für große oder komplexe Objekte.
Die Serialisierung bietet Standardfunktionen zum Speichern und späteren Neuerstellen des Objekts. Es verwendet ein ausführliches Format, um das gesamte Diagramm der zu speichernden Objekte zu definieren. Nehmen wir beispielsweise an, Sie haben eine verknüpfte Liste und codieren wie unten beschrieben. Bei der Standard-Serialisierung werden alle verknüpften Objekte erkannt und serialisiert. In der Standard-Serialisierung 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 Externalizable-Schnittstelle erweitert die Serializable-Schnittstelle und fügt zwei Methoden hinzu, writeExternal () und readExternal (). Diese werden während der Serialisierung oder Deserialisierung automatisch aufgerufen. Während der Arbeit mit Externalizable sollten wir uns daran erinnern, dass der Standardkonstruktor öffentlich sein sollte, da sonst der Code eine Ausnahme auslöst. Bitte folgen Sie dem folgenden 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 die folgende Ausnahme auslösen:
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
Wir können beobachten, dass das Passwort vertrauliche Informationen sind, daher serialisiere ich es nicht in der Methode writeExternal (ObjectOutput oo) und setze nicht den Wert derselben in readExternal (ObjectInput oi). Das ist die Flexibilität, die Externalizable bietet.
Die Ausgabe des obigen Codes erfolgt wie folgt:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
Wir können beobachten, dass wir den Wert von passWord nicht so einstellen, dass er null ist.
Das gleiche kann auch erreicht werden, indem das Passwortfeld als vorübergehend deklariert wird.
private transient String passWord;
Ich hoffe es hilft. Ich entschuldige mich, wenn ich Fehler gemacht habe. Vielen Dank.
Hauptunterschiede zwischen Serializable
undExternalizable
Serializable
ist eine Marker-Schnittstelle ohne Methoden. Externalizable
Schnittstelle enthält zwei Methoden: writeExternal()
und readExternal()
.Serializable
Schnittstelle implementieren . Der vom Programmierer definierte Serialisierungsprozess wird für Klassen, die die Externalizable
Schnittstelle implementieren, aktiviert.Externalizable
Benutzeroberfläche haben. Sie können verschiedene Versionen Ihres Objekts unterstützen. Wenn Sie implementieren Externalizable
, liegt es in Ihrer Verantwortung, die super
Klasse zu serialisierenSerializable
Verwendet Reflektion zum Konstruieren von Objekten und benötigt keinen arg-Konstruktor. Aber Externalizable
verlangt Öffentlichkeit nicht argument Konstruktor.Weitere Informationen finden Sie im Blog von Hitesh Garg
.
Bei der Serialisierung werden bestimmte Standardverhalten verwendet, um das Objekt zu speichern und später neu zu erstellen. Sie können angeben, in welcher Reihenfolge oder wie mit Referenzen und komplexen Datenstrukturen umgegangen 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 wirklich auf eine 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.
Die Objektserialisierung verwendet die Schnittstellen Serializable und Externalizable. Ein Java-Objekt ist nur serialisierbar. Wenn eine Klasse oder eine ihrer Oberklassen entweder die Schnittstelle java.io.Serializable oder ihre Unterschnittstelle java.io.Externalizable implementiert. Die meisten Java-Klassen sind serialisierbar .
NotSerializableException
: packageName.ClassName
«Um ein Klassenobjekt am Serialisierungsprozess teilzunehmen, muss die Klasse entweder eine serialisierbare oder eine externisierbare Schnittstelle implementieren.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 gespeichert, um diese Objekte wiederherzustellen, selbst 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 {};
InvalidClassException
«Im Deserialisierungsprozess, wenn sich der Wert der lokalen Klasse serialVersionUID von der Klasse des entsprechenden Absenders unterscheidet. dann ist das in Konflikt als
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
Externalisierbare Schnittstelle
Bei externisierbaren Objekten wird vom Container nur die Identität der Klasse des Objekts gespeichert. Die Klasse muss den Inhalt speichern und wiederherstellen. Die externisierbare 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;
}
OptionalDataException
«Die Felder müssen in der gleichen Reihenfolge und Art sein, wie wir sie geschrieben haben. Wenn der Stream nicht übereinstimmt, wird eine 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 geschrieben (verfügbar gemacht) wurden , ObjectOutput
um serialisiert zu werden.
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 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();
}
}
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
Die externisierbare Schnittstelle wurde nicht bereitgestellt, um die Leistung des Serialisierungsprozesses zu optimieren! aber um Mittel zur Implementierung Ihrer eigenen benutzerdefinierten Verarbeitung bereitzustellen und die vollständige Kontrolle über das Format und den Inhalt des Streams für ein Objekt und seine Supertypen zu bieten!
Beispiele hierfür sind die Implementierung von AMF-Remoting (ActionScript Message Format) zum Übertragen nativer Aktionsskriptobjekte über das Netzwerk.
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
Die Standardserialisierung ist etwas ausführlich und setzt ein möglichst breites Verwendungsszenario des serialisierten Objekts voraus. Dementsprechend kommentiert das Standardformat (Serializable) den resultierenden Stream mit Informationen über die Klasse des serialisierten Objekts.
Durch die Externalisierung erhält der Produzent des Objektstroms die vollständige Kontrolle über die genauen Klassenmetadaten (falls vorhanden), die über die minimal erforderliche Identifizierung der Klasse (z. B. ihren Namen) hinausgehen. Dies ist in bestimmten Situationen eindeutig wünschenswert, z. B. in geschlossenen Umgebungen, in denen der Produzent des Objektstroms und sein Verbraucher (der das Objekt aus dem Stream reifiziert) übereinstimmen und zusätzliche Metadaten über die Klasse keinen Zweck erfüllen und die Leistung beeinträchtigen.
Zusätzlich (wie Uri betont) ermöglicht die Externalisierung auch die vollständige Kontrolle über die Codierung der Daten im Stream, die Java-Typen entsprechen. Für ein (erfundenes) Beispiel möchten Sie möglicherweise den Booleschen Wert true als 'Y' und false als 'N' aufzeichnen. Mit der Externalisierung können Sie dies tun.
Vergessen Sie bei der Prüfung von Optionen zur Leistungsverbesserung nicht die benutzerdefinierte Serialisierung. Sie können Java kostenlos das tun lassen, was es gut oder zumindest gut genug macht , und benutzerdefinierten Support für das bieten, was es schlecht macht. Dies ist normalerweise viel weniger Code als die vollständige Unterstützung von Externalizable.
Es gibt so viele Unterschiede zwischen Serializable und Externalizable, aber wenn wir den Unterschied zwischen benutzerdefiniertem Serializable (überschriebenes writeObject () & readObject ()) und Externalizable vergleichen, stellen wir fest, dass die benutzerdefinierte Implementierung eng mit der ObjectOutputStream-Klasse verbunden ist, wo wir uns wie im Fall Externalizable befinden Stellen Sie eine Implementierung von ObjectOutput bereit, die eine ObjectOutputStream-Klasse oder eine andere wie org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream sein kann
Im Falle einer externalisierbaren 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 hinzugefügt, um dies besser zu erklären. Bitte checken Sie den Objektfall von Externalizable ein / aus. 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 schwierig zu bedienen sein.
Grundsätzlich Serializable
handelt es sich um eine Markierungsschnittstelle, die impliziert, 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
. Externalizable
Ermöglicht dem Implementierer zu entscheiden, wie ein Objekt serialisiert wird, wobei Serializable
Objekte standardmäßig serialisiert werden.
Einige Unterschiede:
Für die Serialisierung ist kein Standardkonstruktor dieser Klasse erforderlich, da Object, da JVM dasselbe mithilfe der Reflection-API erstellt. Im Falle einer Externalisierung ist ein Konstruktor ohne Argument erforderlich, da die Steuerung programmgesteuert ist und die deserialisierten Daten später über Setter dem Objekt zugewiesen werden.
Wenn der Benutzer bei der Serialisierung bestimmte zu überspringende Eigenschaften überspringen möchte, muss er diese Eigenschaften als vorübergehend markieren. Für die Externalisierung ist umgekehrt nichts erforderlich.
Wenn für eine Klasse Unterstützung für die Abwärtskompatibilität erwartet wird, wird empfohlen, Externalizable zu verwenden. Die Serialisierung unterstützt das Fortbestehen von defaultObject. Wenn die Objektstruktur beschädigt ist, treten beim Deserialisieren Probleme auf.