Następny wpis powstały z dekompozycji już istniejących ☺️. Przed Tobą deserializacja obiektów w języku Java, czyli jak się prezentuje odtwarzanie stanu zapisanego wcześniej obiektu. To będzie kontynuacja artykułu o serializacji, w którym pokazuję jak robić w drugą stronę.
DESERIALIZACJA OBIEKTÓW W JĘZYKU JAVA JAKO PRZYWRACANIE ICH DO ŻYCIA!
Jak możesz się domyślać, deserializacja polega na "odmrożeniu" obiektu ze strumienia bajtów na normalny, "używalny" obiekt javowy 😜. Skorzystamy z tego samego przykładu ukazanego w artykule o serializacji, ja go może przypomnę. Konstruktor klasy "Point":
import java .io.Serializable;
public class Point implements Serializable {
private static final long serialVersionUID = 13L;
private final int x, y;
public Point() {
this(0, 0);
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
}
Zwrócę uwagę na pewne charakterystyczne elementy, które są niezbędne do procesu serializacji:
- interfejs "Serializable" (wyjątkowo nie wymaga implementacji żadnych metod, lecz musi być zaimplementowany przez klasę),
- finalna stała statyczna "serialVersionUID".
To są NIEZBĘDNE rzeczy jakie klasa musi mieć, żeby proces serializacji przebiegał pomyślnie w obie strony. Interfejs "Serializable" otwiera furtkę do serializacji obiektów danej klasy, a "serialVersionUID" umożliwia zapis i odczyt obiektów nawet po edycji danych składowych. Jest to bardzo ważna składowa - jeżeli jej nie określisz, to klasa po zmianie danych składowych wygeneruje nowy, a to z kolei uniemożliwi Ci dalszą serializację i deserializację obiektów tej samej klasy!!! Więcej szczegółów w załączonym artykule.
DO RZECZY!
Teraz przybliżmy sobie metodę do deserializacji:
import java .io.*;
public class Launcher {
private final Point pointA, pointB, pointC;
public Launcher() {
try {
deserialize();
printPoints();
} catch (Exception e) {
e.printStackTrace();
}
}
private void deserialize() throws IOException, ClassNotFoundException {
FileInputStream fileInputStream = new FileInputStream("save.data");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
pointA = (Point)objectInputStream.readObject();
pointB = (Point)objectInputStream.readObject();
pointC = (Point)objectInputStream.readObject();
objectInputStream.close();
}
private void printPoints() {
PrintStream printStream = System.out;
printStream.println(pointA);
printStream.println(pointB);
printStream.println(pointC);
}
}
Zaczyna się podobnie jak poprzednio - w konstruktorze jest wejście do bloku "try-catch" (bo deserializacja obiektów w języku Java ma prawo się wyłożyć), a w nim metoda przywracająca stan poprzednio zapisanych obiektów. Teraz jednak korzystamy z instancji klas o podobnej nazwie (jednak cały czas innej 🙃). Korzystamy teraz z "FileInputStream" i "ObjectInputStream", natomiast parametry są takie same.
Ciekawie (i nieco bardziej skomplikowanie) zaczyna się niżej, w instrukcjach przypisania. Wywołujemy metodę "readObject", a ponadto rzutujemy rezultat na typ klasy zgodny ze zmienną. To jest konieczność! Druga rzecz to to, że aby mieć gwarancję prawidłowo odczytanych obiektów, należy je odczytać W TAKIEJ SAMEJ kolejności, w jakiej były serializowane!!!
Na koniec jak przy zakończeniu obsługi każdego innego strumienia - zamykamy go metodą "close". Jeżeli kolejność obiektów została zachowana, to powinieneś/powinnaś ujrzeć te same wyniki jakie znalazły się w kodzie źródłowym w konstruktorach klasy "Point" 🏆.
Deserializacja obiektów wymaga rzutowania rezultatu metody "readObject" na odpowiedni typ klasy. Oprócz tego, konieczne jest deserializowanie w takiej samej kolejności, w jakiej dane obiekty były serializowane.
Tak się kończy szczęśliwie opowieść o przywracaniu obiektów do życia ❤️. Deserializacja obiektów w języku Java wymaga nietypowego podejścia, jednak jeżeli zachowasz wszelkie podane tu środki ostrożności, będzie dobrze 😉👍!