PDA

View Full Version : [JAVA] Problema serializzazione parametrizzata


Hybr1d97
06-03-2015, 21:41
Salve, ho un problema con la serializzazione in java: in sostanza ho una classe "Serializzatore" che dispone di due metodi statici, "serialize" e "deserialize", che ricevono come parametri il nome del file su/da cui salvare e l'oggetto da (de)serializzare. Tuttavia, la deserializzazione sembra non funzionare. Questo è il codice:

public class Serializzatore{

...

public static <E> boolean deserialize(String filename, E objectToSave){
boolean done;

try{

ObjectInputStream stream = new ObjectInputStream(new FileInputStream(filename));
try {
objectToSave = ((E)stream.readObject());
}
catch (ClassNotFoundException e){ done = false; }

stream.close();
done = true;
}
catch(FileNotFoundException e) { done = false; }
catch(IOException e) { done = false; }

return done;
}


public static void main(String args[]){
Integer a = 3;
Serializzatore.serialize("ser.bin", a);

a = 1;
Serializzatore.deserialize("ser.bin",a);


System.out.println(a); //Dovrebbe dare 3, invece dà 1
}
}



Praticamente la modifica di a avviene solo localmente al metodo di deserializzazione, ma in realtà a resta sempre uguale. Come mai?

wingman87
06-03-2015, 23:00
Non è una questione di deserializzazione, semplicemente hai passato a per riferimento ma poi nel metodo non usi il riferimento ma lo sovrascrivi. D'altra parte gli oggetti Integer sono immutabili quindi non avresti comunque potuto modificare l'oggetto.

Hybr1d97
06-03-2015, 23:17
Ma quindi il problema dov'è? Devo prima istanziare un nuovo integer passandogli come argomento l'oggetto deserializzato e poi farci puntare "a"? Non capisco perchè dici che non uso il riferimento. Che io sappia "a" stesso è un riferimento (nel senso che si riferisce a qualcosa, punta), come se fosse un puntatore C, con quell'istruzione dovrei semplicemente farlo puntare ad un oggetto diverso, ma il puntatore resta sempre quello, no?

wingman87
07-03-2015, 09:07
Ho provato a fare un disegno perché mi sembrava più facile da spiegare... Come vedi nello stack "a" contiene un riferimento all'oggetto Integer con valore 1. Contiene il riferimento, non l'oggetto. Quando chiami deserialize viene allocato nuovo spazio nello stack e, tra le altre cose, viene assegnato a "objectToSave" lo stesso valore che era contenuto in a cioè un riferimento all'oggetto Integer nello heap.
Il disegno si ferma qui.

Ora, quando in deserialize viene eseguita l'istruzione
objectToSave = ((E)stream.readObject());
Viene creato un nuovo oggetto nello heap e il suo riferimento viene scritto in objectToSave, quindi come vedi:
- l'Integer puntato da a non viene toccato
- il valore di a (cioè il riferimento all'integer) non viene toccato

Hybr1d97
07-03-2015, 09:21
Ah :muro: il fatto è che credevo che gli oggetti in java fossero passati per riferimento, nel senso che il parametro formale di un metodo credevo rimanesse lo stesso riferimento che gli passavo (sia puntatore che oggetto). Ma quindi come posso risolvere così da lavorare su a anche nel metodo?

wingman87
07-03-2015, 09:24
Io risolverei cambiando la firma del metodo, potresti restituire l'oggetto deserializzato invece del boolean. Perderesti il boolean però d'altra parte se qualcosa va male potresti restituire null.

Hybr1d97
07-03-2015, 19:56
Risolto! Grazie mille ;) comunque per ovviare alla mancanza del boolean ho messo il throws con le eccezioni nella firma del metodo così le gestisce direttamente il chiamante, visto che le necessità possono variare. Unico problema è il fatto che posso usare solo un file per oggetto, perchè la serializzazione che ho fatto con ObjectOutputStream va a creare un nuovo file e sovrascrive l'ononimo. Non c'è un modo per leggere e scrivere sequenzialmente, pur avendo chiuso e riaperto lo stream?