unserialize - ¿Cuál es la diferencia entre Serializable y Externalizable en Java?
unserialize java (12)
¿Cuál es la diferencia entre Serializable
y Externalizable
en Java?
¡La interfaz Externalizable 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 los contenidos de la secuencia de un objeto y sus supertipos.
Ejemplos de esto es la implementación de AMF (Formato de mensaje de ActionScript) para transferir objetos de script de acción nativos a través de la red.
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 completo Externalizable.
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 al implementador decidir cómo se serializa un objeto, mientras que Serializable
serializa los objetos de forma predeterminada.
Diferencias clave entre Serializable
y Externalizable
- Interfaz de marcador :
Serializable
es una interfaz de marcador sin ningún método.Externalizable
interfazExternalizable
contiene dos métodos:writeExternal()
yreadExternal()
. - Proceso de serialización : el proceso de serialización predeterminado se iniciará para las clases que implementen la interfaz
Serializable
. El proceso de serialización definido por el programador se iniciará para las clases que implementen la interfazExternalizable
. - Mantenimiento : Los cambios incompatibles pueden romper la serialización.
- Compatibilidad y control con versiones anteriores : si tiene que admitir varias versiones, puede tener control total con la interfaz
Externalizable
. Puedes soportar diferentes versiones de tu objeto. Si implementaExternalizable
, es su responsabilidad serializar lasuper
clase. - constructor No-arg público :
Serializable
utiliza la reflexión para construir un objeto y no requiere ningún constructor arg. PeroExternalizable
exige constructor público no arg.
Consulte el blog de Hitesh Garg
para más detalles.
Existen tantas diferencias entre Serializable y Externalizable, pero cuando comparamos la diferencia entre Serializable personalizado (sobrescrita writeObject () & readObject ()) y Externalizable, encontramos que la implementación personalizada está estrechamente vinculada con la clase ObjectOutputStream, como en el caso Externalizable, nosotros mismos proporcionar una implementación de ObjectOutput que puede ser de 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 añadido código de ejemplo para explicar mejor. por favor marque dentro / fuera del objeto caso de Externalizable. Estos no están vinculados a ninguna implementación directamente.
Donde como Outstream / Instream están fuertemente vinculados a las clases. Podemos extender ObjectOutputStream / ObjectInputStream pero será un poco difícil de usar.
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 enlazada y un código como el siguiente, luego la serialización predeterminada descubrirá todos los objetos que están vinculados y se serializará. 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. Mientras trabajamos con Externalizable, debemos recordar que el constructor predeterminado debe ser público, de lo contrario, el código generará 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 se lanzará debajo de la excepción:
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
Podemos observar que la contraseña es información confidencial, por lo que no la estoy serializando en el método writeExternal (ObjectOutput oo) y no estoy configurando el valor de la misma en readExternal (ObjectInput oi). Esa es la flexibilidad que proporciona Externalizable.
La salida del código anterior es como se muestra a continuación:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
Podemos observar que no estamos configurando el valor de passWord por lo que es nulo.
Lo mismo se puede lograr al declarar el campo de contraseña como transitorio.
private transient String passWord;
Espero eso ayude. Me disculpo si cometí algún error. Gracias.
La serialización utiliza ciertos comportamientos predeterminados para almacenar y luego recrear el objeto. Puede especificar en qué orden o cómo manejar las referencias y las estructuras de datos complejas, pero eventualmente se trata de usar el comportamiento predeterminado para cada campo de datos primitivos.
La externalización se utiliza en los casos excepcionales en los que realmente desea almacenar y reconstruir su objeto de una manera completamente diferente y sin utilizar 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.
Para agregar a las otras respuestas, al implementar 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 averiguar cómo calcular y desmarcar tus objetos.
En la versión anterior de Java, la reflexión era muy lenta, por lo que la serialización de gráficos de objetos grandes (por ejemplo, en aplicaciones RMI cliente-servidor) era un problema de rendimiento. Para manejar esta situación, se proporcionó la interfaz java.io.Externalizable
, que es como java.io.Serializable
pero con mecanismos escritos a medida para realizar las funciones de cálculo y desajustes (debe implementar los métodos readExternal
y writeExternal
en su clase). Esto le proporciona los medios para sortear el cuello de botella del rendimiento de la reflexión.
En las versiones recientes de Java (desde luego, la versión 1.3, ciertamente), 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 de Externalizable
con una JVM moderna.
Además, el mecanismo de serialización Java integrado no es el único, puede obtener reemplazos de terceros, como la serialización JBoss, que es considerablemente más rápido, y es un reemplazo directo para el valor predeterminado.
Un gran inconveniente de Externalizable
es que debe mantener esta lógica usted mismo: si agrega, elimina o cambia un campo en su clase, tiene que cambiar sus métodos writeExternal
/ readExternal
para readExternal
en cuenta.
En resumen, Externalizable
es una reliquia de los días Java 1.1. Realmente ya no hay necesidad de eso.
Sólo para completar, la palabra clave transient
también cierra la brecha entre los dos.
Si solo desea serializar parte de su objeto, simplemente configure campos específicos como transient
, márquelos para que no se conserven e implemente Serializable
.
Serialización en Java
Java proporciona un mecanismo, denominado Serialización de objetos, que permite al usuario almacenar la estructura y los datos de un Objeto en un archivo externo. Este archivo contiene información sobre el objeto; tipo de objeto, tipo de miembros y datos que poseen esos miembros.
Interfaz externalizable:
Al igual que la interfaz
Serializable
,Externizable
también almacena un objeto con sus datos en un archivo externo que luego podemos recuperar. Pero hay alguna diferencia:En la serialización, todos los miembros / variables en el objeto se serializan en el archivo externo, mientras que en la Externalización, podemos mencionar específicamente qué miembros queremos que se almacenen. Dado que la serialización serializa toda la clase, no necesitamos escribir métodos para leer y escribiendo el archivo externo. Pero
Externalizable
requiere dos métodos; a saber,readExternal()
ywriteExternal()
Referencia completa: Diferencia entre serialización y externalización.
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
La serialización predeterminada es un tanto detallada y asume 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 del flujo de objetos y su consumidor (que reifica el objeto del flujo) se comparan, y los metadatos adicionales sobre la clase no tienen ningún propósito y degradan el rendimiento.
Además, como lo señala Uri, la externalización también proporciona un control completo sobre la codificación de los datos en el flujo correspondiente a los tipos de Java. Por ejemplo, puede que desee grabar el verdadero booleano como ''Y'' y el falso como ''N''. La externalización te permite hacer eso.
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 externalizable.
La serialización de objetos produce un flujo con información sobre las clases de Java para los objetos que se están guardando. Para los objetos serializables, se mantiene información suficiente para restaurar esos objetos incluso si existe 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 {};
- La interfaz de serialización no tiene métodos ni campos y sirve solo para identificar la semántica de ser serializable. Para serializar / deserializar una clase, podemos usar los métodos predeterminados writeObject y readObject (o) podemos anular los métodos writeObject y readObject de una clase.
- JVM tendrá control completo en la serialización del objeto. use una palabra clave transitoria para evitar que el miembro de datos se serialice.
- Aquí, los objetos serializables se reconstruyen directamente desde el flujo sin ejecutar
-
InvalidClassException
«En el proceso de deserialización, si el valor de la clase local serialVersionUID es diferente de la clase del remitente correspondiente. entonces el resultado está en conflicto comojava.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
- Los valores de los campos no transitorios y no estáticos de la clase se serializan.
Para los objetos Externalizables, el contenedor solo 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;
}
- La interfaz Externalizable tiene dos métodos, un objeto externalizable debe implementar un método writeExternal y readExternal para guardar / restaurar el estado de un objeto.
- El programador tiene que cuidar de qué objetos ser serializados. Como programador, tenga cuidado de la serialización. Por lo tanto, aquí la palabra clave transitoria no restringirá ningún objeto en el proceso de serialización.
- Cuando se reconstruye un objeto Externalizable, se crea una instancia utilizando el constructor público no-arg, luego se llama el método readExternal. Los objetos serializables se restauran al leerlos desde un ObjectInputStream.
OptionalDataException
«Los campos DEBEN ESTAR EN EL MISMO PEDIDO Y TIPO tal como los escribimos. Si hay alguna falta de coincidencia de tipo en la secuencia, se lanza la excepción 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(); }
Los campos de instancia de la clase que escribieron (expuestos) en
ObjectOutput
se serializan.
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
- ¿Qué es la serialización de objetos?
- Serialización de objetos: Preguntas frecuentes