- łatwy - zapisać stan obiektu w pliku tekstowym zapisując każde pole
- łatwiejszy - wykorzystać mechanizm serializacji obiektu.
Mając na myśli łatwiejszy rozważam tutaj korzyści z serializacji (szybkości implementacji oraz elastyczności programowania).
Serializacja obiektów w java jest swego rodzaju zrzutem obiektu z pamięci RAM to strumienia bajtowego zapisanego na np dysku twardym. Do tego rodzaju operacji są wykorzystywane klasy strumieniowe : ObjectOutputStream, ObjectInputStream oraz odpowiednie metody void writeObject(Object o), Object readObject(). Standardowo klasy, które są dostępne w javie od razu posiadają metody do zapisu/odczytu wartości danego typu oraz co ważne: implementują intefrejs Serializable np:
writeUTF(String s) / readUTF()
writeFloat(float f) / readFloat()
writeDobule(double d) / read Double()
etc...
Zatem jak zapisać/odczytać ?
Podrzucam spakowany projekt NetBeans SerializationExample.
Najpierw trzeba utworzyć obiekt ObjectOutputStream aby móc w nim zapisać dane, które nas interesują.
// Metoda do zapisu danych w pliku test.temp
try
{
ObjectOutputStream MyObjectOutputStream = new ObjectOutputStream(new FileOutputStream("test.temp"));
MyObjectOutputStream.writeUTF(serializujTextField.getText());
MyObjectOutputStream.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
Następnie gdy zapisaliśmy w pliku test.temp spróbujmy zamknąć program, a po uruchomieniu wcisnąć przycisk odczytaj.
Udostępnię teraz kod, który odczytuje z pliku test.temp naszą zapisaną wartość w String.
try {
ObjectInputStream OIS = new ObjectInputStream(new FileInputStream("test.temp"));
serializujLabel.setText(OIS.readUTF());
OIS.close();
}
catch (IOException ex)
{
}
Działa !
Jednak dla bardziej złożonych problemów nie wystarczy zapisać samego pola obiektu (String), a trzeba zapisać cały obiekt własnej klasy wraz z jego wszystkimi polami typów prostych (int,char,boolean,float,itp) oraz pola referencyjne (MojaJakasKlasa,JFrame,JButton, itp itp). Zatem stwórzmy klasę o nazwie Osoba, która będzie przechowywać dwa pola imię, nazwisko.
Przykładowy kod klasy z setterami, getterami i konstruktorem:
public class Osoba{
private String imie;
private String nazwisko;
public String getImie() {
return imie;
}
public void setImie(String imie) {
this.imie = imie;
}
public String getNazwisko() {
return nazwisko;
}
public void setNazwisko(String nazwisko) {
this.nazwisko = nazwisko;
}
public Osoba(String imie, String nazwisko) {
this.imie = imie;
this.nazwisko = nazwisko;
}
}
Skoro dodałem już klasę Osoba to niech obiekt tej klasy znajdzie się w głównej formie MyJFrame i zostanie utworzony jeśli naciśniemy przycisk serializuj w panelu Serializacja obiektu Osoba. Następnie zamknijmy program i włączmy go ponownie i kliknijmy odczytaj. Widać, że nie możemy odczytać z ObjectInputStream ponieważ nasza klasa nie implementuje intefrejsu Serializable.
Powstanie wyjątek typu:
java.io.InvalidClassException: serializationexample.Osoba; serializationexample.Osoba; class invalid for deserialization
Zatem musimy zmienić nagłówek klasy na następujący:
public class Osoba implements Serializable.
Zapiszmy zmiany w projekcie, utwórzmy obiekt osoba wpisując imię i nazwisko w polach tekstowych, kliknijmy serializuj, następnie zamknijmy, otwórzmy program i wciśnijmy przycisk odczytaj. Widać, że program już działa jak powinien.
Jedyną znaczną różnicą wobec przykładu z typem String jest to, że musimy dokonać konwersji zawężającej do typu Osoba:
o = (Osoba) MyObjectInputStreamOsoba.readObject();
MyObjectInputStreamOsoba.close();
imieLabel.setText(o.getImie());
nazwiskoLabel.setText(o.getNazwisko());
Dodam na koniec ciekawostkę, że intefrejs Serializable nie posiada żadnych metod do przedefiniowania i nazywa się znacznikowym intefrejsem. Potrzeba istnienia takich intefrejsów polega na tym, że wyznaczają typ naszej klasy:
if (O instance of Serializable)
Powyższa linijka kodu zwróci wartość true, a kompilator będzie wiedział, że obiekty można zapisywać/odczywać.
Jeżeli mamy rozbudowaną hierarchię dziedziczenia oraz klasa Osoba posiada inne pola obiektowe np. Adres a, HistoriaChoroby h, to nie musimy się martwić o zapisanie tych pól albowiem java rekurencyjnie zapisuje wszystkie pola klasy (muszą oczywiście implementować interfejs Serializable).
Jeśli mamy bardzo rozbudowaną klasę, która używa mechanizmu szeregowania(serializacji), a nie podoba się nam, że wszystkie pola są zapisywane możemy w prosty sposób powiedzieć kompilatorowi aby nie zapisywał danego pola klasy. Do tego celu musimy użyć słowa kluczowego javy transient przykład:
private transient String maloWaznaZmienna;
Orginalny post z mojej domeny rpiesnikowski.pl
Adres postu: http://gold.uwb.edu.pl/~st_robpie/WP/?p=25
Robert.
0 comments:
Post a Comment