Serialización. Ficheros de Objetos en Java. Interface Serializable.

1. Serialización y persistencia de objetos
La serialización es la transformación de un objeto en una secuencia de bytes que pueden ser posteriormente leídos para reconstruir el objeto original.
El objeto serializado pueda guardarse en un fichero o puede enviarse por red para reconstruirlo en otro lugar. Puede crearse en un sistema Windows y enviarlo, por ejemplo, a otro sistema que utilice Linux.
Guardar objetos de forma que existan cuando la aplicación haya terminado se conoce como persistencia.
Para poder transformar el objeto en una secuencia de bytes, el objeto debe ser serializable.
Un objeto es serializable si su clase implementa la interface Serializable.
La interface Serializable se encuentra en el paquete java.io Es una interface vacía. No contiene ningún método.
public interface Serializable{}
Sirve para indicar que los objetos de la clase que lo implementa se pueden serializar. Solo es necesario que una clase la implemente para que la máquina virtual pueda serializar los objetos.
Si un objeto contiene atributos que son referencias a otros objetos éstos a su vez deben ser serializables.
Todos los tipos básicos Java son serializables, así como los arrays y los String.
2. Persistencia de Objetos en Ficheros
Para escribir objetos en un fichero binario en Java se utiliza la clase ObjectOutputStream derivada de OutputStream.
Un objeto ObjectOutputStream se crea a partir de un objeto FileOutputStream asociado al fichero.
El constructor de la clase es:
ObjectOutputStream(OutputStream nombre);
Lanza una excepción IOException.
Por ejemplo, las instrucciones para crear el fichero personas.dat para escritura de objetos serían éstas:
FileOutputStream fos = new FileOutputStream ("/ficheros/personas.dat");                                           
ObjectOutputStream salida = new ObjectOutputStream (fos);
La clase proporciona el método writeObject(Object objeto) para escribir el objeto en el fichero. Lanza una IOException
El método defaultWriteObject() de la clase ObjectOutputStream realiza de forma automática la serialización de los objetos de una clase. Este método se invoca en el método writeObject().
defaultWriteObject() escribe en el stream de salida todo lo necesario para reconstruir los objetos:
- La clase del objeto.
- Los miembros de la clase (atributos).
- Los valores de los atributos que no sean static o transient.
El método defaultReadObject() de la clase ObjectInputStream realiza la deserialización de los objetos de una clase. Este método se invoca en el método readObject().
Ejemplo 1:
Ejemplo de persistencia de objetos en fichero en Java
Programa que escribe 3 objetos de tipo Persona en el fichero personas.dat.
La clase Persona es la siguiente:
//Clase Persona
import java.io.Serializable;

public class Persona implements Serializable{

    private String nif;
    private String nombre;
    private int edad;

    public Persona() {
    }

    public Persona(String nif, String nombre, int edad) {                                                         
        this.nif = nif;
        this.nombre = nombre;
        this.edad = edad;
    }

    public int getEdad() {
        return edad;
    }

    public void setEdad(int edad) {
        this.edad = edad;
    }

    public String getNif() {
        return nif;
    }

    public void setNif(String nif) {
        this.nif = nif;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
}

//Clase Principal
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Serial1 {

    public static void main(String[] args) {

        FileOutputStream fos = null;
        ObjectOutputStream salida = null;
        Persona p;

        try {
            //Se crea el fichero
            fos = new FileOutputStream("/ficheros/personas.dat");                                                 
            salida = new ObjectOutputStream(fos);
   
            //Se crea el primer objeto Persona
            p = new Persona("12345678A","Lucas González", 30);
   
            //Se escribe el objeto en el fichero
            salida.writeObject(p);
   
            //Se crea el segundo objeto Persona
            p = new Persona("98765432B","Anacleto Jiménez", 28);
   
            //Se escribe el objeto en el fichero
            salida.writeObject(p);
   
            //Se crea el tercer objeto Persona
            p = new Persona("78234212Z","María Zapata", 35);
   
            //Se escribe el objeto en el fichero
            salida.writeObject(p);
           
        } catch (FileNotFoundException e) {
                 System.out.println("1"+e.getMessage());                                                          
        } catch (IOException e) {
                 System.out.println("2"+e.getMessage());
        } finally {
            try {
                if(fos!=null){
                   fos.close();
                }
                if(salida!=null){
                   salida.close();
                }
            } catch (IOException e) {
                     System.out.println("3"+e.getMessage());
            }
        }

    }
}

3. Serialización y Herencia
Para serializar objetos de una jerarquía solamente la clase base tiene que implementar el interface Serializable. No es necesario que las clases derivadas implementen la interfaz.
Si una clase es serializable lo son también todas sus clases derivadas.
Ejemplo 2:
Ejemplo de herencia y serialización:
Programa Java que escribe en un fichero tres objetos de tipo Empleado. Empleado es una clase derivada de la clase Persona del ejemplo anterior. Como la clase Persona es serializable, no es necesario indicar que la clase Empleado también lo es. Empleado es serializable por el hecho de heredar de Persona.
//Clase Empleado
public class Empleado extends Persona{

    private double sueldo;
 
    public Empleado(String nif, String nombre, int edad, double sueldo) {                                         
        super(nif, nombre, edad);
        this.sueldo = sueldo;
    }

    public Empleado() {
    }

    public double getSueldo() {
        return sueldo;
    }
 
    public void setSueldo(double sueldo) {                                                                        
        this.sueldo = sueldo;
    }
}

//Clase principal
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Serial3 {

    public static void main(String[] args) {
 
        FileOutputStream fos = null;
        ObjectOutputStream salida = null;
        Empleado emp;
  
        try {
            fos = new FileOutputStream("/ficheros/personas.dat");
            salida = new ObjectOutputStream(fos);
            emp = new Empleado("12345678A","Lucas González", 30, 1200.40);                                        
            salida.writeObject(emp);
            emp = new Empleado("98765432B","Anacleto Jiménez", 28, 1000);
            salida.writeObject(emp);
            emp = new Empleado("78234212Z","María Zapata", 35, 1100.25);
            salida.writeObject(emp);
           
        } catch (FileNotFoundException e) {
                 System.out.println(e.getMessage());                                                              
        } catch (IOException e) {
                 System.out.println(e.getMessage());
        } finally {
            try {
                if(fos!=null) fos.close();
                if(salida!=null) salida.close();
            } catch (IOException e) {
                     System.out.println(e.getMessage());
            }
        }
    }
}

4. Serialización y clases compuestas
Cuando una clase contiene un atributo que es una referencia a otro objeto, la clase a la que pertenece dicho atributo también debe ser serializable.  
Ejemplo 3:
Ejemplo de serialización de una clase compuesta:
Programa java que escribe en un fichero tres objetos de tipo Alumno. Alumno es una clase derivada de Persona y contiene un atributo Fecha:
//Clase Fecha
import java.io.Serializable;

public class Fecha implements Serializable{

    private int dia;
    private int mes;
    private int año;

    public Fecha(int dia, int mes, int año) {                                                                     
        this.dia = dia;
        this.mes = mes;
        this.año = año;
    }
    public Fecha() {
    }
    public int getAño() {
        return año;
    }

    public void setAño(int año) {
        this.año = año;
    }

    public int getDia() {
        return dia;
    }

    public void setDia(int dia) {
        this.dia = dia;
    }

    public int getMes() {
        return mes;
    }

    public void setMes(int mes) {                                                                                 
        this.mes = mes;
    }
   
}

//Clase Alumno
public class Alumno extends Persona{

    private Fecha fechaMatricula;

    public Alumno(String nif, String nombre, int edad, Fecha fechaMatricula) {                                    
        super(nif, nombre, edad);
        this.fechaMatricula = new Fecha();
        setFechaMatricula(fechaMatricula);
    }

    public Alumno() {
    }

    public Fecha getFechaMatricula() {
        return fechaMatricula;
    }

    public void setFechaMatricula(Fecha fechaMatricula) {
        this.fechaMatricula.setDia(fechaMatricula.getDia());                                                      
        this.fechaMatricula.setMes(fechaMatricula.getMes());
        this.fechaMatricula.setAño(fechaMatricula.getAño());
    }  
   
}

//Clase principal
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Serial5 {

    public static void main(String[] args) {                                                                      
 
        FileOutputStream fos = null;
        ObjectOutputStream salida = null;
        Alumno a;
        Fecha f;
  
        try {
            fos = new FileOutputStream("/ficheros/alumnos.dat");
            salida = new ObjectOutputStream(fos);
            f = new Fecha(5,9,2011);
            a = new Alumno("12345678A","Lucas González", 20, f);
            salida.writeObject(a);
            f = new Fecha(7,9,2011);
            a = new Alumno("98765432B","Anacleto Jiménez", 19, f);                                                
            salida.writeObject(a);
            f = new Fecha(8,9,2011);
            a = new Alumno("78234212Z","María Zapata", 21, f);
            salida.writeObject(a);
           
        } catch (FileNotFoundException e) {
                 System.out.println(e.getMessage());
        } catch (IOException e) {
                 System.out.println(e.getMessage());
        } finally {
            try {
                if(fos!=null) fos.close();
                if(salida!=null) salida.close();
            } catch (IOException e) {
                     System.out.println(e.getMessage());                                                          
            }
        }
    }
}

5. Leer objetos de ficheros
Para leer los objetos contenidos en un fichero binario que han sido almacenados mediante ObjectOutputStream se utiliza la clase ObjectInputStream derivada de InputStream.
Un objeto ObjectInputStream se crea a partir de un objeto FileInputStream asociado al fichero.
El constructor de la clase es:
ObjectInputStream(InputStream nombre);
Lanza una excepción IOException.
Por Ejemplo,  las instrucciones para crear el objeto ObjectInputStream para lectura de objetos del fichero personas.dat serían éstas:
FileInputStream fis = new FileInputStream ("/ficheros/personas.dat");                                             
ObjectInputStream entrada = new ObjectInputStream (fis);
La clase proporciona el método readObject() que devuelve el objeto del fichero (tipo Object).
Es necesario hacer un casting para guardarlo en una variable del tipo adecuado.
Lanza una IOException
Ejemplo 4:
Ejemplo de lectura de objetos contenidos en un fichero en Java
Programa que lee los objetos del fichero creado en el Ejemplo 1:
//Clase principal
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class Serial2 {

    public static void main(String[] args) {

        FileInputStream fis = null;
        ObjectInputStream entrada = null;
        Persona p;

        try {

            fis = new FileInputStream("/ficheros/personas.dat");
            entrada = new ObjectInputStream(fis);
            p = (Persona) entrada.readObject(); //es necesario el casting
            System.out.println(p.getNif() + " " + p.getNombre() + " " + p.getEdad());                             
            p = (Persona) entrada.readObject();
            System.out.println(p.getNif() + " " + p.getNombre() + " " + p.getEdad());
            p = (Persona) entrada.readObject();
            System.out.println(p.getNif() + " " + p.getNombre() + " " + p.getEdad());                             
   
        } catch (FileNotFoundException e) {
                 System.out.println(e.getMessage());
        } catch (ClassNotFoundException e) {
                 System.out.println(e.getMessage());
        } catch (IOException e) {
                 System.out.println(e.getMessage());
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
                if (entrada != null) {
                    entrada.close();
                }
            } catch (IOException e) {
                     System.out.println(e.getMessage());
            }
        }
    }
}

Ejemplo 5:
Programa Java que lee los objetos del fichero creado en el Ejemplo 2:
//Clase Principal
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;


public class Serial4 {

    public static void main(String[] args) {
 
        FileInputStream fis = null;
        ObjectInputStream entrada = null;
        Empleado emp;
  
        try {
            fis = new FileInputStream("/ficheros/personas.dat");
            entrada = new ObjectInputStream(fis);
            emp = (Empleado) entrada.readObject();
            System.out.println(emp.getNif() + " "
                               + emp.getNombre() + " " + emp.getEdad() + " " + emp.getSueldo());                  
            emp = (Empleado) entrada.readObject();
            System.out.println(emp.getNif() + " "
                               + emp.getNombre() + " " + emp.getEdad() + " " + emp.getSueldo());
            emp = (Empleado) entrada.readObject();
            System.out.println(emp.getNif() + " "
                               + emp.getNombre() + " " + emp.getEdad() + " " + emp.getSueldo());                  
        } catch (FileNotFoundException e) {
                 System.out.println(e.getMessage());
        } catch (ClassNotFoundException e) {
                 System.out.println(e.getMessage());
        } catch (IOException e) {
                 System.out.println(e.getMessage());
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
                if (entrada != null) {
                    entrada.close();
                }
            } catch (IOException e) {
                     System.out.println(e.getMessage());
            }
        }
    }
}
Ejemplo 6:
Programa Java que lee los objetos del fichero creado en el Ejemplo 3:
//Clase Principal
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import persona.Alumno;

public class Serial6 {

    public static void main(String[] args) {
 
        FileInputStream fis = null;
        ObjectInputStream entrada = null;
        Alumno a;
  
        try {
            fis = new FileInputStream("/ficheros/alumnos.dat");
            entrada = new ObjectInputStream(fis);
            a = (Alumno) entrada.readObject();
            System.out.println(a.getNif() + " " + a.getNombre() + " " + a.getEdad()                               
                               + " " + a.getFechaMatricula().getDia() + "-"
                               + a.getFechaMatricula().getMes() + "-"
                               + a.getFechaMatricula().getAño());
            a = (Alumno) entrada.readObject();
            System.out.println(a.getNif() + " " + a.getNombre() + " " + a.getEdad()
                               + " " + a.getFechaMatricula().getDia() + "-"
                               + a.getFechaMatricula().getMes() + "-"
                               + a.getFechaMatricula().getAño());
            a = (Alumno) entrada.readObject();
            System.out.println(a.getNif() + " " + a.getNombre() + " " + a.getEdad()                               
                               + " " + a.getFechaMatricula().getDia() + "-"
                               + a.getFechaMatricula().getMes() + "-"
                               + a.getFechaMatricula().getAño());
        } catch (FileNotFoundException e) {
                 System.out.println(e.getMessage());
        } catch (ClassNotFoundException e) {
                 System.out.println(e.getMessage());
        } catch (IOException e) {
                 System.out.println(e.getMessage());
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
                if (entrada != null) {
                    entrada.close();
                }
            } catch (IOException e) {
                     System.out.println(e.getMessage());
            }
        }
    }
}

6. El modificador transient
Un atributo transient no se serializa.
En el siguiente ejemplo, la clase Cliente tiene dos atributos: el nombre del cliente y la contraseña. El atributo contraseña es transient por lo tanto si se serializa para escribir un objeto Cliente en un fichero solo se escribirá el atributo nombre.
//Clase Cliente
public class Cliente implements Serializable{                                                                     
     private String nombre;
     private transient String passWord;
     public Cliente(String nombre, String passWord) {                                                             
              this.nombre=nombre;
              this.passWord= passWord;
     }
}

10 comentarios:

  1. El archivo al que se hace la referencia (alumnos.dat). Es un archivo que debo tner guardado en la carpeta de mi proyecto o a que se refiere esa parte? estoy confundida..

    fis = new FileInputStream("/ficheros/alumnos.dat");

    ResponderEliminar
    Respuestas
    1. Esta instrucción indica que el fichero alumnos.dat está dentro de una carpeta llamada ficheros que debe estar en la raíz de la unidad donde se encuentra en proyecto. Si estás trabajando con un proyecto que tienes en el pendrive la carpeta ficheros debe estar en la raiz del pendrive.

      Eliminar
    2. Estoy ocupando netBeans, en que parte debo agregar la carpeta "ficheros"???? Gracias

      Eliminar
  2. Me podrias orientar para que el siguiente codigo pueda realizar la consulta a traves dell DNI o numero de expediente:

    private void btcBuscarActionPerformed(java.awt.event.ActionEvent evt) {
    // TODO add your handling code here:
    Object nombreArchivo = archivo;
    try{
    try (ObjectInputStream filein = new ObjectInputStream(new FileInputStream((String) nombreArchivo))){
    Object expediente = filein.readObject();
    Object dni = filein.readObject();
    Object apellidos = filein.readObject();
    Object nombres = filein.readObject();
    Object direccion = filein.readObject();
    Object telefono = filein.readObject();
    Object foto = filein.readObject();
    txtNroExpediente.setText((String) expediente);
    txtDni.setText((String) dni);
    txtApellidos.setText((String) apellidos);
    txtNombres.setText((String) nombres);
    txtDireccion.setText((String) direccion);
    txtTelefono.setText((String) telefono);
    lblFoto.setIcon((Icon) foto);
    if(filein!=null){
    filein.close();
    }
    } catch (ClassNotFoundException ex) {
    Logger.getLogger(JDPacientes.class.getName()).log(Level.SEVERE, null, ex);
    }
    }catch(IOException e){}
    }

    ResponderEliminar
  3. Por Favor me podrias ayudar con esto? Urgente Gracias
    Construir Servidor de paginas web con funcionalidades basicas que pueda atender solicitudes hechas por varias instancias de navegador(cliente) al mismo tiempo.

    ResponderEliminar
  4. Por favor, ayuda estoy intentado para un vector de objetos y no sale :c

    ResponderEliminar
  5. Que pasa si en lugar de ir metiendo objeto por objeto quiero meter un arreglo de objetos, ya lo intente y no me lo permite
    public void ward(String name){

    try{
    FileOutputStream fout= new FileOutputStream(name);
    ObjectOutputStream oos=new ObjectOutputStream(fout);//objecto para mandar a escribir al archivo
    for(k=0;k<=index;k++)
    {
    oos.writeObject(libros[k]); //el problema es acá
    }
    oos.close();
    }catch(EOFException e){
    e.printStackTrace();
    }catch(FileNotFoundException e){
    e.printStackTrace();
    }catch(IOException e){
    e.printStackTrace();
    }
    }

    ResponderEliminar
  6. alguna alma caritativa me puede ayudar .Cuando pone en leer el primer ejercicio binario :
    "//es necesario el casting" que deobo poner por que me atasque y no doy con ello
    muchas gracias y perdon por las molestias

    ResponderEliminar
  7. public void ejecute(String aux){
    Statement sentencias=null;
    try{
    sentencias = conn1.createStatement();
    sentencias.executeUpdate(aux);
    sentencias.close();
    }catch(SQLException ex){
    ex.printStackTrace();
    }
    }


    public void leersql(String fichero){
    String aux;
    try{
    String cadena;
    aux="";
    FileReader f = new FileReader(fichero);
    BufferedReader b = new BufferedReader(f);
    while((cadena = b.readLine())!=null) {
    if(cadena.startsWith("/*")||cadena.startsWith("--")){
    }else{
    if(!cadena.endsWith(";")){
    aux+=cadena;
    }
    if(cadena.endsWith(";")){
    aux+=cadena;
    ejecute(aux);
    aux="";
    }
    }
    }
    System.out.println("Treminado");
    b.close();
    f.close();
    }
    catch (IOException e){
    System.out.println(e.getStackTrace());
    }
    }

    public void altaReparaciones(){
    String fechaE,fechaS;
    ArrayList matriculas=new ArrayList();
    System.out.print("Fecha de entrada (dd/mm/aa): ");
    fechaE=sc.next();
    System.out.print("Fecha de salida (dd/mm/aa): ");
    fechaS=sc.next();

    System.out.println("Listado de coches:");
    System.out.println("--------------------------");
    try{
    int contador=0,cocheSelec=0,precio,cantidad;
    String SQL = "SELECT * FROM coches",nombre;
    Statement stmt = conn1.createStatement();
    ResultSet rs = stmt.executeQuery(SQL);
    while (rs.next()) {
    contador++;
    matriculas.add(rs.getString("matricula"));
    System.out.println(contador+", "+rs.getString("matricula") + ", " + rs.getString("marca")+", "+rs.getString("modelo"));
    }


    System.out.println("Elige uno de los coches:");
    cocheSelec=sc.nextInt();

    PreparedStatement ps=null;
    ps=conn1.prepareStatement("INSERT INTO `reparaciones` VALUES (NULL,?,?,?)");
    ps.setString(1, fechaE);
    ps.setString(2, fechaS);
    ps.setString(3, matriculas.get(cocheSelec-1));
    ps.executeUpdate();
    ps.close();


    System.out.println("Reparacion dada de alta, inserta los materiales usados");
    System.out.println("-----------------------------------------");
    System.out.print("Nombre:");
    nombre=sc.next();
    System.out.print("Cantidad:");
    cantidad=sc.nextInt();
    System.out.print("Precio:");
    precio=sc.nextInt();

    rs.close();
    stmt.close();

    }catch(Exception e){
    }
    }

    ResponderEliminar