¿Qué significa serializable?

136

¿Qué significa exactamente que una clase esté Serializableen Java? O en general, para el caso ...

Ritwik Bose
fuente
10
@skaffman Esto es lo que dice para la clase Serializable: Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.
Ritwik Bose
32
Una gran explicación si ya sabes lo que significa serializado y deserializado. (No es un cumplido). Dichas definiciones lo ayudan a comprender mejor el problema técnicamente una vez, y solo una vez, ya tiene algún conocimiento al respecto.
Xonatron

Respuestas:

132

La serialización es la persistencia de un objeto de la memoria a una secuencia de bits, por ejemplo, para guardarlo en el disco. La deserialización es todo lo contrario: leer datos del disco para hidratar / crear un objeto.

En el contexto de su pregunta, es una interfaz que, si se implementa en una clase, esta clase puede ser serializada y deserializada automáticamente por diferentes serializadores.

Oded
fuente
2
También tenga en cuenta que todos los campos no marcados explícitamente de lo contrario también se serializarán. Esto significa que puede guardar fácilmente una estructura de datos compleja simplemente serializando el objeto raíz.
Thorbjørn Ravn Andersen
1
Entonces, cuando hablamos de "Objetos", ¿nos referimos al objeto instanciado por una clase, o simplemente a cualquier "Objeto de software" como ensamblajes, archivos, etc.? Y si es lo último, ¿es solo una forma estandarizada de enviar datos entre programas y entornos?
Sunburst275
1
@ Sunburst275: en este caso, esta es la representación en memoria de una clase en memoria, es decir, una instancia de una clase (no hay un punto real para hablar sobre la serialización de ensamblajes, ya que generalmente están en el disco como archivos que pueden simplemente ser enviado como está).
Oded
44

Aunque la mayoría de los usuarios ya han dado la respuesta, pero me gustaría agregar un ejemplo para aquellos que lo necesitan para explicar la idea:

Digamos que tienes una persona de clase como la siguiente:

public class Person implements java.io.Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public String firstName;
    public String lastName;
    public int age;
    public String address;

    public void play() {
        System.out.println(String.format(
                "If I win, send me the trophy to this address: %s", address));
    }
    @Override
    public String toString() {
        return String.format(".....Person......\nFirst Name = %s\nLast Name = %s", firstName, lastName);
    }
}

y luego creas un objeto como este:

Person william = new Person();
        william.firstName = "William";
        william.lastName = "Kinaan";
        william.age = 26;
        william.address = "Lisbon, Portugal";

Puede serializar ese objeto a muchas secuencias. Haré eso en dos transmisiones:

Serialización a salida estándar:

public static void serializeToStandardOutput(Person person)
            throws IOException {
        OutputStream outStream = System.out;
        ObjectOutputStream stdObjectOut = new ObjectOutputStream(outStream);
        stdObjectOut.writeObject(person);
        stdObjectOut.close();
        outStream.close();
    }

Serialización a un archivo:

public static void serializeToFile(Person person) throws IOException {
        OutputStream outStream = new FileOutputStream("person.ser");
        ObjectOutputStream fileObjectOut = new ObjectOutputStream(outStream);
        fileObjectOut.writeObject(person);
        fileObjectOut.close();
        outStream.close();
    }

Luego:

Deserializar desde archivo:

public static void deserializeFromFile() throws IOException,
            ClassNotFoundException {
        InputStream inStream = new FileInputStream("person.ser");
        ObjectInputStream fileObjectIn = new ObjectInputStream(inStream);
        Person person = (Person) fileObjectIn.readObject();
        System.out.println(person);
        fileObjectIn.close();
        inStream.close();
    }
William Kinaan
fuente
Gracias. Creo que lo tengo ahora.
Sunburst275
40

Significa que las instancias de la clase pueden convertirse en una secuencia de bytes (por ejemplo, para guardarse en un archivo) y luego volver a convertirse en clases nuevamente. Esta recarga podría ocurrir en una instancia diferente del programa, o incluso en una máquina diferente. Sin embargo, la serialización (en cualquier idioma) involucra todo tipo de problemas, especialmente cuando tiene referencias a otros objetos dentro del serializable.

David
fuente
15

Aquí hay una explicación detallada de la serialización : (mi propio blog)

Publicación por entregas:

La serialización es el proceso de serialización del estado de un objeto que se representa y almacena en forma de una secuencia de bytes. Esto se puede almacenar en un archivo. El proceso para leer el estado del objeto del archivo y restaurarlo se llama deserialización.

¿Cuál es la necesidad de la serialización?

En la arquitectura moderna, siempre es necesario almacenar el estado del objeto y luego recuperarlo. Por ejemplo, en Hibernate, para almacenar un objeto debemos hacer que la clase Serializable. Lo que hace es que una vez que el estado del objeto se guarda en forma de bytes, se puede transferir a otro sistema que luego puede leer desde el estado y recuperar la clase. El estado del objeto puede provenir de una base de datos o una jvm diferente o de un componente separado. Con la ayuda de la serialización podemos recuperar el estado del objeto.

Código de ejemplo y explicación:

Primero echemos un vistazo a la clase de artículo:

public class Item implements Serializable{

    /**
    *  This is the Serializable class
    */
    private static final long serialVersionUID = 475918891428093041L;
    private Long itemId;
    private String itemName;
    private transient Double itemCostPrice;
    public Item(Long itemId, String itemName, Double itemCostPrice) {
        super();
        this.itemId = itemId;
        this.itemName = itemName;
        this.itemCostPrice = itemCostPrice;
      }

      public Long getItemId() {
          return itemId;
      }

     @Override
      public String toString() {
          return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
       }


       public void setItemId(Long itemId) {
           this.itemId = itemId;
       }

       public String getItemName() {
           return itemName;
       }
       public void setItemName(String itemName) {
            this.itemName = itemName;
        }

       public Double getItemCostPrice() {
            return itemCostPrice;
        }

        public void setItemCostPrice(Double itemCostPrice) {
             this.itemCostPrice = itemCostPrice;
        }
}

En el código anterior se puede ver que la clase Item implementa Serializable .

Esta es la interfaz que permite que una clase sea serializable.

Ahora podemos ver que una variable llamada serialVersionUID se inicializa en Variable larga. El compilador calcula este número basándose en el estado de la clase y los atributos de la clase. Este es el número que ayudará a la jvm a identificar el estado de un objeto cuando lee el estado del objeto del archivo.

Para eso podemos echar un vistazo a la documentación oficial de Oracle:

El tiempo de ejecución de serialización asocia a cada clase serializable un número de versión, llamado serialVersionUID, que se utiliza durante la deserialización para verificar que el emisor y el receptor de un objeto serializado hayan cargado clases para ese objeto que sean compatibles con respecto a la serialización. Si el receptor ha cargado una clase para el objeto que tiene un serialVersionUID diferente al de la clase del remitente correspondiente, la deserialización dará como resultado una InvalidClassException. Una clase serializable puede declarar explícitamente su propio serialVersionUID declarando un campo llamado "serialVersionUID" que debe ser estático, final y de tipo largo: CUALQUIER MODIFICADOR DE ACCESO estático final largo serialVersionUID = 42L; Si una clase serializable no declara explícitamente un serialVersionUID, entonces el tiempo de ejecución de serialización calculará un valor de serialVersionUID predeterminado para esa clase en función de varios aspectos de la clase, como se describe en la Especificación de serialización de objetos Java (TM). Sin embargo, se recomienda encarecidamente que todas las clases serializables declaren explícitamente los valores serialVersionUID, ya que el cálculo predeterminado serialVersionUID es muy sensible a los detalles de la clase que pueden variar según las implementaciones del compilador y, por lo tanto, pueden dar lugar a inesperadas InvalidClassExceptions durante la deserialización. Por lo tanto, para garantizar un valor de serialVersionUID consistente en diferentes implementaciones de compilador de Java, una clase serializable debe declarar un valor de serialVersionUID explícito. También se recomienda encarecidamente que las declaraciones explícitas serialVersionUID utilicen el modificador privado siempre que sea posible,

Si ha notado que hay otra palabra clave que hemos usado que es transitoria .

Si un campo no es serializable, debe marcarse como transitorio. Aquí marcamos el itemCostPrice como transitorio y no queremos que se escriba en un archivo

Ahora echemos un vistazo a cómo escribir el estado de un objeto en el archivo y luego leerlo desde allí.

public class SerializationExample {

    public static void main(String[] args){
        serialize();
       deserialize();
    } 

    public static void serialize(){

         Item item = new Item(1L,"Pen", 12.55);
         System.out.println("Before Serialization" + item);

         FileOutputStream fileOut;
         try {
             fileOut = new FileOutputStream("/tmp/item.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(item);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved in /tmp/item.ser");
           } catch (FileNotFoundException e) {

                  e.printStackTrace();
           } catch (IOException e) {

                  e.printStackTrace();
           }
      }

    public static void deserialize(){
        Item item;

        try {
                FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
                ObjectInputStream in = new ObjectInputStream(fileIn);
                item = (Item) in.readObject();
                System.out.println("Serialized data is read from /tmp/item.ser");
                System.out.println("After Deserialization" + item);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
               e.printStackTrace();
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        }
     }
}

En lo anterior podemos ver un ejemplo de serialización y deserialización de un objeto.

Para eso usamos dos clases. Para serializar el objeto, hemos utilizado ObjectOutputStream. Hemos utilizado el método writeObject para escribir el objeto en el archivo.

Para la deserialización, hemos utilizado ObjectInputStream que lee del objeto del archivo. Utiliza readObject para leer los datos del objeto del archivo.

El resultado del código anterior sería como:

Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]

Tenga en cuenta que itemCostPrice del objeto deserializado es nulo ya que no se escribió.

Pritam Banerjee
fuente
2
Gracias por esta explicación detallada.
Promesa Preston
Esta es una buena explicación! ¡Gracias! Pero para ser honesto, esta entrada se ve mucho más limpia que la de tu blog. De todos modos, esto ayudó mucho!
Sunburst275
11

La serialización implica guardar el estado actual de un objeto en una secuencia y restaurar un objeto equivalente de esa secuencia. La secuencia funciona como un contenedor para el objeto

Jigar Joshi
fuente
1
Esta definición parece más precisa. Gracias.
Promesa Preston
6

Serializable se llama como una interfaz, pero es más como un indicador del subsistema de serialización, en tiempo de ejecución. Dice que este objeto se puede guardar. Se guardarán todas las variables de instancia de Objetos con la excepción de los objetos no serializables y los que marcan volátiles.

Imagine que su aplicación puede cambiar el color como una opción, sin mantener esa configuración externa, necesitaría cambiar el color cada vez que la ejecuta.

AphexMunky
fuente
55
No es una 'bandera para el compilador'. Es un indicador del subsistema de serialización, en tiempo de ejecución.
Marqués de Lorne el
1
@EJP - Gracias, no lo sabía
AphexMunky
Con respeto, ¿por qué escribirlo cuando no sabes que es verdad? También has dejado de lado 'transitorio'. En general, una respuesta pobre, lo siento.
Marqués de Lorne
19
Si no lo hubiera escrito, no habría sido corregido y estaría peor. Todas las otras respuestas también se han dejado transitorias. Ni siquiera escribiste una respuesta, solo estás trolleando a otras personas.
AphexMunky
4

La serialización es una técnica para almacenar o escribir objetos y datos en archivos. Mediante el uso de ObjectOutputStreamy FileOutputStreamclases. Estas clases tienen sus métodos específicos para persistir los objetos. me gustawriteObject();

para una clara explicación con figuras. Vea aqui para mas informacion

Mdhar9e
fuente
2

Presentar desde otra perspectiva. La serialización es un tipo de interfaz llamada 'interfaz de marcador'. Una interfaz de marcador es una interfaz que no contiene declaraciones de métodos, sino que simplemente designa (o "marca") una clase que implementa la interfaz como que tiene alguna propiedad. Si entiendes el polimorfismo, esto tendrá mucho sentido. En el caso de la interfaz de marcador serializable, el método ObjectOutputStream.write (Object) fallará si su argumento no implementa la interfaz. Este es un error potencial en Java, podría haber sido ObjectOutputStream.write (Serializable)

Muy recomendable: Lectura del ítem 37 de Effective Java por Joshua Bloch para aprender más

nanospeck
fuente
2

Serialización: escritura del estado del objeto en un archivo / red o en cualquier lugar. (Formulario compatible con objeto Java medio para presentar el formulario compatible o el formulario compatible con la red)

Deserialización: Lectura del estado del objeto desde un archivo / red o en cualquier lugar. (Archivo medio / formulario compatible con red para formulario compatible con objetos Java)

Asif Mushtaq
fuente
1

Solo para agregar a las otras respuestas y con respecto a la generalidad. La serialización a veces se conoce como archivado, por ejemplo en Objective-C.

Greg Sexton
fuente