¿Cuál es la diferencia entre Serializable y Externalizable en Java?


Respuestas:


267

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.Externalizablese proporcionó la interfaz, que es similar java.io.Serializablea los mecanismos escritos para realizar las funciones de clasificación y de clasificación (es necesario implementar readExternaly writeExternalmé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 Externalizablecon 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 Externalizablees que debe mantener esta lógica usted mismo: si agrega, elimina o cambia un campo en su clase, debe cambiar sus métodos writeExternal/ readExternalpara tenerlo en cuenta.

En resumen, Externalizablees una reliquia de los días de Java 1.1. Realmente ya no es necesario.


61
No de acuerdo con estos puntos de referencia: [ code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking] , la serialización manual (usando externizable) es mucho, mucho más rápida que usando la serialización predeterminada de java. Si la velocidad es importante para su trabajo, definitivamente escriba su propio serializador.
volni

66
actualización al nuevo enlace github.com/eishay/jvm-serializers/wiki sugerido por @Jack
noquery

3
El "java-manual" en github.com/eishay/jvm-serializers/wiki no no utilizar Externalizable, lo que implicaría el uso de ObjectOutputStream. Consulte github.com/eishay/jvm-serializers/wiki/ToolBehavior para obtener un enlace al código. En cambio, es un código escrito a mano que usa DataOutputStream, por lo que no sufre las cosas que hacen que ObjectOutputStream sea lento (como hacer un seguimiento de las instancias de objetos y admitir ciclos de objetos).
Esko Luontola

77
Tener que mantener la lógica usted mismo es solo una desventaja si la clase nunca cambia y nunca tiene que leer en versiones persistentes de datos antiguos. Si desea la libertad de cambiar su clase sin tener que escribir un código infernal para deserializar las versiones anteriores, Externalizablees de gran ayuda .
Tim Boudreau

2
Solo tenía que escribir una colección personalizada y tengo que decir que Externalizableme 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.
Haravikk

37

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.


22

Diferencias clave entre SerializableyExternalizable

  1. Interfaz de marcador : Serializablees la interfaz de marcador sin ningún método. ExternalizableLa interfaz contiene dos métodos: writeExternal()y readExternal().
  2. Proceso de serialización : el proceso de serialización predeterminado se iniciará para las clases que implementan la Serializableinterfaz. El proceso de serialización definido por el programador se iniciará para las clases que implementan la Externalizableinterfaz.
  3. Mantenimiento : los cambios incompatibles pueden interrumpir la serialización.
  4. Compatibilidad y control hacia atrás : si tiene que admitir varias versiones, puede tener control total con la Externalizableinterfaz. Puede admitir diferentes versiones de su objeto. Si implementa Externalizable, es su responsabilidad serializar la superclase
  5. constructor público sin argumentos : Serializableutiliza la reflexión para construir objetos y no requiere ningún constructor de argumentos. Pero Externalizableexige un constructor público sin argumentos.

Consulte el blog por Hitesh Gargpara más detalles.


1
(3) es incorrecto. Hay un gran repertorio de cambios que puede realizar en una clase sin interrumpir la deserialización de los objetos existentes, y agregar miembros serializables es sin duda uno de ellos. Eliminarlos es otra. Consulte el capítulo Control de versiones de objetos de la Especificación de serialización de objetos Java.
Marqués de Lorne

1
Frase reformulada.
Ravindra babu

Gracias por compartir el enlace a la especificación de serialización.
JL_SO

21

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.


55
Utilizamos Externalizable para grandes colecciones de "ID seleccionados": fue mucho más eficiente la externalización como más o menos un recuento y una matriz de entradas primitivas, que la serialización predeterminada. Es un caso de uso muy simple, nada "especial" o "único".
Thomas W

9

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.

ingrese la descripción de la imagen aquí


Interfaz serializable

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 {};
  • La interfaz de serialización no tiene métodos o 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. usar palabras clave transitorias para evitar que el miembro de datos se serialice.
  • Aquí los objetos serializables se reconstruyen directamente desde la secuencia sin ejecutar
  • 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
  • Los valores de los campos no transitorios y no estáticos de la clase se serializan.

Interfaz externalizable

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;
}
  • 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 qué objetos se serializarán. Como programador se encarga de la serialización. Entonces, 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 sin argumentos, luego se llama al método readExternal. Los objetos serializables se restauran al leerlos desde un ObjectInputStream.
  • 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 ObjectOutputserializarse.


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


7

¡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.


7

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.


2

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.


2

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.


1
¿Podrías elaborarlo más? Mientras lo leo, no entiendo lo que estás tratando de decir. Además, si pudiera formatear el texto con algunos párrafos y ejemplos, esta podría ser una gran respuesta.
Shirkam

0

Básicamente, Serializablees una interfaz de marcador que implica que una clase es segura para la serialización y la JVM determina cómo se serializa. Externalizablecontiene 2 métodos readExternaly writeExternal. Externalizablepermite que el implementador decida cómo se serializa un objeto, mientras que Serializableserializa los objetos de la manera predeterminada.


0

Algunas diferencias:

  1. 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.

  2. 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.

  3. 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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.