¿Cuál es la diferencia entre Serializable
y Externalizable
en Java?
¿Cuál es la diferencia entre Serializable
y Externalizable
en Java?
Respuestas:
Para agregar a las otras respuestas, mediante la implementación java.io.Serializable
, obtiene la capacidad de serialización "automática" para los objetos de su clase. No es necesario implementar ninguna otra lógica, simplemente funcionará. El tiempo de ejecución de Java utilizará la reflexión para descubrir cómo ordenar y desarmar sus objetos.
En versiones anteriores de Java, la reflexión era muy lenta, por lo que serializar gráficos de objetos grandes (por ejemplo, en aplicaciones RMI cliente-servidor) era un problema de rendimiento. Para manejar esta situación, java.io.Externalizable
se proporcionó la interfaz, que es similar java.io.Serializable
a los mecanismos escritos para realizar las funciones de clasificación y de clasificación (es necesario implementar readExternal
y writeExternal
métodos en su clase). Esto le brinda los medios para sortear el cuello de botella del rendimiento de la reflexión.
En versiones recientes de Java (1.3 en adelante, sin duda), el rendimiento de la reflexión es mucho mejor de lo que solía ser, por lo que este es un problema mucho menor. Sospecho que sería difícil obtener un beneficio significativo Externalizable
con una JVM moderna.
Además, el mecanismo de serialización Java incorporado no es el único, puede obtener reemplazos de terceros, como la serialización JBoss, que es considerablemente más rápida y es un reemplazo directo para el valor predeterminado.
Una gran desventaja Externalizable
es que debe mantener esta lógica usted mismo: si agrega, elimina o cambia un campo en su clase, debe cambiar sus métodos writeExternal
/ readExternal
para tenerlo en cuenta.
En resumen, Externalizable
es una reliquia de los días de Java 1.1. Realmente ya no es necesario.
Externalizable
es de gran ayuda .
Externalizable
me queda mucho mejor, ya que no quiero generar matrices con espacios vacíos u objetos de marcador de posición, además de la interfaz explícita que puede manejar la herencia, lo que significa mi sub sincronizado -class puede agregar fácilmente el bloqueo alrededor de la llamada a writeExternal()
. Entonces, sí, Externalizable sigue siendo muy relevante, ciertamente para objetos grandes o complejos.
La serialización proporciona una funcionalidad predeterminada para almacenar y luego recrear el objeto. Utiliza un formato detallado para definir el gráfico completo de los objetos que se almacenarán, por ejemplo, suponga que tiene una lista vinculada y codifica como se muestra a continuación, luego la serialización predeterminada descubrirá todos los objetos que están vinculados y se serializarán. En la serialización predeterminada, el objeto se construye completamente a partir de sus bits almacenados, sin llamadas de constructor.
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Users/Desktop/files/temp.txt"));
oos.writeObject(linkedListHead); //writing head of linked list
oos.close();
Pero si desea una serialización restringida o no desea que una parte de su objeto se serialice, use Externalizable. La interfaz Externalizable extiende la interfaz Serializable y agrega dos métodos, writeExternal () y readExternal (). Estos se llaman automáticamente durante la serialización o deserialización. Al trabajar con Externalizable, debemos recordar que el constructor predeterminado debería ser público; de lo contrario, el código arrojará una excepción. Por favor, siga el siguiente código:
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);
}
}
}
Aquí, si comenta el constructor predeterminado, el código arrojará la siguiente excepción:
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
Podemos observar que, como la contraseña es información confidencial, no la serializo en el método writeExternal (ObjectOutput oo) y no configuro el valor de la misma en readExternal (ObjectInput oi). Esa es la flexibilidad que proporciona Externalizable.
El resultado del código anterior es el siguiente:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
Podemos observar que no estamos estableciendo el valor de passWord, por lo que es nulo.
Lo mismo también se puede lograr declarando el campo de contraseña como transitorio.
private transient String passWord;
Espero eso ayude. Pido disculpas si cometí algún error. Gracias.
Diferencias clave entre Serializable
yExternalizable
Serializable
es la interfaz de marcador sin ningún método. Externalizable
La interfaz contiene dos métodos: writeExternal()
y readExternal()
.Serializable
interfaz. El proceso de serialización definido por el programador se iniciará para las clases que implementan la Externalizable
interfaz.Externalizable
interfaz. Puede admitir diferentes versiones de su objeto. Si implementa Externalizable
, es su responsabilidad serializar la super
claseSerializable
utiliza la reflexión para construir objetos y no requiere ningún constructor de argumentos. Pero Externalizable
exige un constructor público sin argumentos.Consulte el blog por Hitesh Garg
para más detalles.
La serialización usa ciertos comportamientos predeterminados para almacenar y luego recrear el objeto. Puede especificar en qué orden o cómo manejar referencias y estructuras de datos complejas, pero eventualmente se reduce al uso del comportamiento predeterminado para cada campo de datos primitivo.
La externalización se usa en los raros casos en los que realmente desea almacenar y reconstruir su objeto de una manera completamente diferente y sin usar los mecanismos de serialización predeterminados para los campos de datos. Por ejemplo, imagine que tiene su propio esquema único de codificación y compresión.
La serialización de objetos utiliza las interfaces serializables y externalizables. Un objeto Java solo es serializable. si una clase o cualquiera de sus superclases implementa la interfaz java.io.Serializable o su subinterfaz, java.io.Externalizable. La mayoría de la clase java son serializables .
NotSerializableException
: packageName.ClassName
«Para participar un objeto de clase en el proceso de serialización, la clase debe implementar una interfaz serializable o externa.La serialización de objetos produce una secuencia con información sobre las clases de Java para los objetos que se están guardando. Para los objetos serializables, se mantiene suficiente información para restaurar esos objetos incluso si está presente una versión diferente (pero compatible) de la implementación de la clase. La interfaz serializable se define para identificar las clases que implementan el protocolo serializable:
package java.io;
public interface Serializable {};
InvalidClassException
«En el proceso de deserialización, si la clase local serialVersionUID valor de es diferente de la clase del remitente correspondiente. entonces resulta en conflicto como
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
Para los objetos externalizables, solo el contenedor guarda la identidad de la clase del objeto; la clase debe guardar y restaurar los contenidos. La interfaz externalizable se define de la siguiente manera:
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
«Los campos DEBEN ESTAR EN EL MISMO ORDEN Y TIPO tal como los escribimos. Si hay alguna discrepancia de tipo de la secuencia, arroja OpcionalDataException.
@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();
}
Los campos de instancia de la clase que se escribieron (expuestos) para ObjectOutput
serializarse.
Ejemplo « implementa 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;
}
Ejemplo « implementa 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();
}
}
Ejemplo
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();
}
}
}
@ver
¡La interfaz externalizable en realidad no se proporcionó para optimizar el rendimiento del proceso de serialización! ¡pero para proporcionar medios para implementar su propio procesamiento personalizado y ofrecer un control completo sobre el formato y el contenido de la secuencia para un objeto y sus super tipos!
Ejemplos de esto es la implementación de comunicación remota AMF (formato de mensaje de ActionScript) para transferir objetos de script de acción nativos a través de la red.
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
La serialización predeterminada es algo detallada, y supone el escenario de uso más amplio posible del objeto serializado y, en consecuencia, el formato predeterminado (serializable) anota la secuencia resultante con información sobre la clase del objeto serializado.
La externalización le da al productor del flujo de objetos un control completo sobre los metadatos de clase precisos (si los hay) más allá de la identificación mínima requerida de la clase (por ejemplo, su nombre). Esto es claramente deseable en ciertas situaciones, como entornos cerrados, donde el productor de la secuencia de objetos y su consumidor (que reifica el objeto de la secuencia) coinciden, y los metadatos adicionales sobre la clase no sirven para nada y degradan el rendimiento.
Además (como señala Uri), la externalización también proporciona un control completo sobre la codificación de los datos en la secuencia correspondiente a los tipos de Java. Para un ejemplo (artificial), es posible que desee registrar boolean verdadero como 'Y' y falso como 'N'. La externalización te permite hacer eso.
Al considerar las opciones para mejorar el rendimiento, no olvide la serialización personalizada. Puede dejar que Java haga lo que hace bien, o al menos lo suficientemente bueno, de forma gratuita y proporcionar soporte personalizado para lo que hace mal. Esto suele ser mucho menos código que el soporte externo externo completo.
Existen muchas diferencias entre Serializable y Externalizable, pero cuando comparamos la diferencia entre Serializable personalizado (writeObject () y readObject () anulado y Externalizable, descubrimos que la implementación personalizada está estrechamente vinculada con la clase ObjectOutputStream donde, como en el caso de Externalizable, nosotros mismos proporcionar una implementación de ObjectOutput que puede ser la clase ObjectOutputStream o podría ser alguna otra como org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream
En caso de interfaz 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();
}
He agregado un código de muestra para explicar mejor. Por favor, compruebe el caso de entrada / salida de objeto de Externalizable Estos no están vinculados a ninguna implementación directamente.
Donde como Outstream / Instream están estrechamente vinculados a las clases. Podemos extender ObjectOutputStream / ObjectInputStream pero será un poco difícil de usar.
Básicamente, Serializable
es una interfaz de marcador que implica que una clase es segura para la serialización y la JVM determina cómo se serializa. Externalizable
contiene 2 métodos readExternal
y writeExternal
. Externalizable
permite que el implementador decida cómo se serializa un objeto, mientras que Serializable
serializa los objetos de la manera predeterminada.
Algunas diferencias:
Para la serialización no hay necesidad de un constructor predeterminado de esa clase porque Object porque JVM construye lo mismo con la ayuda de Reflection API. En caso de externalización, se requiere un constructor sin arg, porque el control está en manos de programmar y luego asigna los datos deserializados al objeto a través de setters.
En la serialización, si el usuario desea omitir ciertas propiedades para ser serializadas, entonces tiene que marcar esas propiedades como transitorias, y viceversa, no es necesario para la externalización.
Cuando se espera soporte de compatibilidad con versiones anteriores para cualquier clase, se recomienda ir con Externalizable. La serialización admite la persistencia defaultObject y si la estructura del objeto está rota, causará problemas al deserializar.