У меня есть класс Person и класс BankAccount следующим образом (извините, код на испанском sh):
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
}
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
}
Как видите, в классе BankAccount есть Person поле, в котором указано лицо, которому оно принадлежит. Таким образом, у меня может быть много учетных записей BankAccount, связанных с одним и тем же лицом, поэтому я могу получить все учетные записи BankAccount, связанные с одним лицом, и использовать их как единое целое, и это прекрасно работает. Тем не менее, у меня есть небольшая проблема при сохранении данных Person и BankAccount в файлы и последующем чтении их при повторном запуске программы ...
Следующий класс - это тот, который читает и записывает данные. Важными методами здесь являются cargarArchivos (), который загружает содержимое файлов в ArrayLists, actualizarArchivoPersonas (), который обновляет файл Person, и actualizarArchivoCuentas (), который делает то же самое для BankAccounts. Эти методы обновления вызываются всякий раз, когда я вносю изменения в ArrayLists в других частях кода.
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<Persona> personas = new ArrayList<>();
private static final ArrayList<CuentaBancaria> cuentasBancarias = new ArrayList<>();
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 < 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<Persona> getListaPersonas() {
return personas;
}
public static ArrayList<CuentaBancaria> 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;
}
}
Проблема заключается в том, что при перезапуске программы и перезагрузке двух файлов в ArrayLists каждый BankAccount по-прежнему имеет Person с правильными данными, но этот Person теперь является объектом, отличным от Person, который хранится в персонализированном ArrayList, даже если они имеют одинаковые значения в своих полях.
Чтобы это исправить, у меня есть метод reasociar () также в этом классе, цель которого состоит в том, чтобы заново связать каждую учетную запись BankAccount с каждым лицом, соответственно, на основе этого nif лица (которое является уникальным идентификатором для каждого лица) сразу после загрузки данных из файлов. Если я не использую метод reasociar (), чтобы заставить Person в каждом BankAccount фактически указывать на правильного Person в personas ArrayList, объект Person в каждом BankAccounts - это разные элементы в памяти от Person, которые были прочитаны и сохранены для Персонал ArrayList, даже если с каждым BankAccount все еще связаны «правильный» nif, имя и фамилия владельца. Так что метод reasociar () отлично справляется с задачей, и благодаря этому все прекрасно работает при перезапуске программы.
Но мой вопрос ... Есть ли правильный способ сделать это, когда я пишу два файлов данных и считывания их при перезапуске программы, указатели объектов остаются согласованными без необходимости их повторной привязки? Надеюсь, я все хорошо объяснил ... Спасибо