title: Storing and reading objects that contain other objects in Java with ObjectOutputStream ObjectInputStream
body: <p>I have a class Person and a class BankAccount as follows (sorry, the code is in spanish):</p>
  
  <pre class="lang-java prettyprint-override"><code>package aplicacion.banco;
  
  import java.io.Serializable;
  
  public class Persona implements Serializable {
  
      String nif; // se asume unico para cada Persona
      String nombre; // nombre
      String apellidos; // apellidos
  
      public Persona(String nif, String nombre, String apellidos) {
          this.nif = nif;
          this.nombre = nombre;
          this.apellidos = apellidos;
      }
      // bunch of methods including setters and getters
  }
  </code></pre>
  
  <pre class="lang-java prettyprint-override"><code>package aplicacion.banco;
  
  import java.io.Serializable;
  
  public class CuentaBancaria implements Serializable {
  
      int numeroCuenta; // se asume unico para cada CuentaBancaria/CuentaBancariaVip
      Persona persona; // objeto Persona al que pertenece esta Cuenta
      double saldo; // saldo disponible
  
      public CuentaBancaria(int numeroCuenta, Persona persona, double saldo) {
          this.numeroCuenta = numeroCuenta;
          this.persona = persona;
          this.saldo = saldo;
      }
  
      public CuentaBancaria(int numeroCuenta, Persona persona) {
          this(numeroCuenta, persona, 0d);
      }
      // bunch of methods including setters and getters
  }
  </code></pre>
  
  <p>As you can see, the BankAccount class has a Person field which indicates the Person who it belongs to. This way, I can have many BankAccounts associated to the same Person, thus I can get all the BankAccounts associated to a single Person and operate them as a whole, and it works just fine. However, I have a little problem when storing the data of Person and BankAccount into files and then reading it back when relaunching the program...</p>
  
  <p>The next class is the one that reads and writes the data. The important methods here are cargarArchivos(), which loads the content of the files into the ArrayLists, actualizarArchivoPersonas() which updates the Person file, and actualizarArchivoCuentas() which does the same for the BankAccounts. These update methods are called whenever I make changes in the ArrayLists in other parts of the code.</p>
  
  <pre class="lang-java prettyprint-override"><code>package aplicacion.banco;
  
  import java.util.ArrayList;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.io.EOFException;
  
  public class OperadorDatos {
  
      private static final ArrayList&lt;Persona&gt; personas = new ArrayList&lt;&gt;();
      private static final ArrayList&lt;CuentaBancaria&gt; cuentasBancarias = new ArrayList&lt;&gt;();
  
      private static final File DIRECTORIO = new File ("data");
      private static final File PERSONAS = new File (DIRECTORIO.getPath() + "/" + "personas.dat");
      private static final File CUENTAS = new File (DIRECTORIO.getPath() + "/" + "cuentas.dat");
  
      /**
       * Comprueba la existencia de los archivos y directorio. Si no existen los crea.
       */
      private static void comprobarArchivos() {
  
          try {
              if (DIRECTORIO.exists()) {
                  if (! PERSONAS.exists()) PERSONAS.createNewFile();
                  if (! CUENTAS.exists()) CUENTAS.createNewFile();
              } else {
                  DIRECTORIO.mkdir();
                  PERSONAS.createNewFile();
                  CUENTAS.createNewFile();
              }
          } catch (Exception e) {
              System.exit(-1);
          }
      }
  
      /**
       * Carga en memoria el contenido de los archivos.
       */
      public static void cargarArchivos() {
  
          comprobarArchivos();
  
          personas.clear();
          cuentasBancarias.clear();
          ObjectInputStream ois;
          try {
              ois = new ObjectInputStream(new FileInputStream(PERSONAS));
              while (true) {
                  Persona p = (Persona)ois.readObject();
                  personas.add(p);
              }
          } catch (EOFException eof) {
              // todo correcto
          } catch (Exception e) {
              e.printStackTrace();
          }
  
          try {
              ois = new ObjectInputStream(new FileInputStream(CUENTAS));
              while (true) {
                  CuentaBancaria cb = (CuentaBancaria)ois.readObject();
                  cuentasBancarias.add(cb);
              }
          } catch (EOFException eof) {
              // todo correcto
          } catch (Exception e) {
              e.printStackTrace();
          }
  
          reasociar();
      }
  
      /**
       * Este metodo se encarga de reasociar cada Cuenta con su Persona al cargar el programa
       * en base al campo NIF que se entiende como clave unica (ya que no puede haber dos Persona con mismo nif)
       * Esto hace falta hacerlo ya que, como estoy serializando objetos que tienen como atributo otros objetos,
       * al volver a cargarlos la asociacion en direcciones de memoria se rompe. Este metodo se encarga de solucionar eso.
       */
      public static void reasociar() {
  
          for (CuentaBancaria cb : cuentasBancarias)
              for (Persona p : personas)
                  if(cb.getPersona().getNif().equals(p.getNif()))
                      cb.setPersona(p);
      }
  
      /**
       * Comprueba si existe una persona con el nif indicado y devuelve un valor de posición
       * @param  nif nif a comprobar
       * @return     numero entero equivalente a la posicion de la persona en el array, -1 si no existe
       */
      public static int comprobarNif(String nif) {
  
          for (int i = 0; i &lt; personas.size(); i++) {
              if (nif.equals(personas.get(i).getNif())) return i;
          }
          return -1;
      }
  
      /**
       * Crea un nuevo objeto Persona a partir de los datos,
       * actualiza el archivo de datos, y devuelve la Persona recien creada
       * @param  nif       NIF
       * @param  nombre    nombre
       * @param  apellidos apellidos
       * @return           el nuevo objeto Persona
       */
      public static Persona crearPersona(String nif, String nombre, String apellidos) {
          Persona p = new Persona(nif,nombre,apellidos);
          personas.add(p);
          actualizarArchivoPersonas();
          return p;
      }
  
      /**
       * Obtiene un objeto Persona a partir de busqueda por NIF
       * @param  nif NIF de la persona a buscar
       * @return     Objeto Persona al que corresponde este NIF, null si no existe.
       */
      public static Persona getPersona(String nif) {
  
          for (Persona p : personas) {
              if (p.getNif().equals(nif)) return p;
          }
  
          return null;
      }
  
      public static ArrayList&lt;Persona&gt; getListaPersonas() {
          return personas;
      }
  
      public static ArrayList&lt;CuentaBancaria&gt; getListaCuentas() {
          return cuentasBancarias;
      }
  
      /**
       * Crea un Objeto CuentaBancaria asociado a la Persona indicada,
       * actualiza el archivo, y devuelve el nuevo Objeto
       * @param  p Objeto Persona al que se asociará la nueva cuenta
       * @return   Objeto CuentaBancaria recién creado
       */
      public static CuentaBancaria crearCuentaBancaria(Persona p) {
          CuentaBancaria cb = new CuentaBancaria(cuentasBancarias.size()+1,p);
          cuentasBancarias.add(cb);
          actualizarArchivoCuentas();
          return cb;
      }
  
      /**
       * Crea un Objeto CuentaBancariaVip asociado a la Persona indicada,
       * actualiza el archivo, y devuelve el nuevo Objeto
       * @param  p Objeto Persona al que se asociará la nueva cuenta
       * @return   Objeto CuentaBancariaVip recién creado
       */
      public static CuentaBancariaVip crearCuentaBancariaVip(Persona p) {
          CuentaBancariaVip cb = new CuentaBancariaVip(cuentasBancarias.size()+1,p);
          cuentasBancarias.add(cb);
          actualizarArchivoCuentas();
          return cb;
      }
  
      /**
       * Actualiza el archivo personas.dat, que contiene informacion de las personas.
       */
      public static void actualizarArchivoPersonas() {
  
          try {
  
              PERSONAS.delete();
              PERSONAS.createNewFile();
              ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(PERSONAS, false));
              for (Persona p : personas) {
                  oos.writeObject(p);
              }
              oos.close();
  
          } catch (Exception e) {
  
          }
      }
  
      /**
       * Actualiza el archivo cuentas.dat, que contiene informacion de las cuentas.
       */
      public static void actualizarArchivoCuentas() {
  
          try {
  
              CUENTAS.delete();
              CUENTAS.createNewFile();
              ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(CUENTAS, false));
              for (CuentaBancaria cb : cuentasBancarias) {
                  oos.writeObject(cb);
              }
              oos.close();
  
          } catch (Exception e) {
  
          }
      }
  
      /**
       * Cuenta la cantidad de cuentas de una persona
       * y el valor total de las cuentas.
       * @param  p Persona cuyas cuentas contar
       * @return   array de dos posiciones, [0] es la cantidad de cuentas, [1] el valor total
       */
      public static double[] contarCuentas(Persona p) {
  
          double[] sum = new double[2];
          for (CuentaBancaria cb : cuentasBancarias) {
              if(cb.getPersona() == p) {
                  sum[0]++;
                  sum[1]+=cb.getSaldo();
              }
          }
          return sum;
      }
  }
  </code></pre>
  
  <p>The problem is that when I restart the program and reload the two files into the ArrayLists, each BankAccount still has a Person with the correct data, but that Person is now a different object from the Person being stored in the personas ArrayList, even if they have the same values in their fields.</p>
  
  <p>To fix this, I have the method reasociar() also in this class, which purpose is to reassociate each BankAccount with each Person accordingly based on that Person nif (which is a unique ID for each Person) right after loading the data from the files. If I don't use the method reasociar() to make the Person in each BankAccount actually point to the correct Person in the personas ArrayList, the object Person in each BankAccounts are different items in memory from the Person that have been read and stored to the personas ArrayList, even if each BankAccount still has the "correct" nif, name and surname of the owner associated. So the method reasociar() does the trick just fine and thanks to it everything works fine when restarting the program.</p>
  
  <p>But my question is... Is there a proper way to do it so when I write the two data files and read them back when I restart the program, the Object pointers stay consistent without needing to reassociate them? I hope I did explain myself well enough... Thank you</p>