Jason. Cała informatyka w jednym miejscu!

Na sam początek mam jedno pytanko. Czy ktoś z Was wie do czego służy serializacja obiektów w języku Java? Wiecie w ogóle że jest taki termin? Jeśli drapiecie się po głowie, to czytajcie uważnie. Nie mówię, że jest to podstawa w rozumieniu języka, natomiast przechowywanie danych w celu zapisu i odczytu może być ciekawym eksperymentem. To co, przekonałem do zmiany decyzji?

SERIALIZACJA OBIEKTÓW W JĘZYKU JAVA. DOKŁADNA CHARAKTERYSTYKA

Jak co artykuł, przejdę najpierw to czystej teorii. "Serializacja" to inaczej przekształcanie obiektów w czysty strumień bajtów chronionych przed zewnętrzną edycją. Kolokwialnie mówiąc, przypomina to takie "zmielenie" obiektów w których dane składowe są zabezpieczane i przechowywane w odrębnym pliku na dysku. Java udostępnia taki system "zamrażania" i odtwarzania danych składowych obiektów, ale w taki sposób żeby móc zrekonstruować stan obiektu sprzed zapisu.

Zanim jednak rozpoczniemy ukazanie przykładu, chcę jeszcze napisać jedną przestrogę: serializacja obiektów powinna być wykorzystywana wtedy i tylko wtedy, gdy jesteśmy święcie przekonani, że dane będą obsługiwane wyłącznie przez Javę. Jeżeli jest inaczej, stanie się to bezużyteczne i konieczne będzie użycie środka zastępczego w postaci eksportu do pliku tekstowego, ponieważ żaden inny język "nie rozumie" działania serializacji języka Java.

PRZYKŁADY ZASTOSOWAŃ

Gry to pierwszy przykład jaki się idealnie nasuwa na użycie tego systemu. Nikt z nas nie chce przechodzić ciągle tego samego etapu po wielu godzinach walki z wrogami lub rozgryzania wyjątkowo skomplikowanej zagadki. Czasy "NES-a" się skończyły, teraz każda produkcja musi mieć system zapisu i odczytu. Jakieś programy przechowujące konfigurację, to również dobry pomysł bo to też jest czymś, co zwykle powinno być "trzymane pod kloszem".

PRZYKŁAD KODU ŹRÓDŁOWEGO

Na razie nakłaniam do przykucia uwagi na poniższy kod źródłowy. Ostrzegam, że on jest dużo większy od większości prezentowanych przykładów:

KLASA "MAIN"

public class Main {
	public static void main(String[] args) {
		new Serialization();
	}
}

KLASA "SERIALIZATION"

import java .io.*;

public class Serialization {
	private static final String SAVE_FILENAME = "save.data";

	private Point pa, pb, pc;

	public Serialization() {
		createInstances();

		try {
			serializePoints();
			//deserializePoints();
		}
		catch (Exception e) {
			e.printStackTrace();
		}

		printPoints();
	}

	private void createInstances() {
		pa = new Point();
		pb = new Point(8, 6);
		pc = new Point(14, 13);
	}

	// serializacja obiektów - definicja funkcji
	private void serializePoints() throws IOException {
		FileOutputStream fos = new FileOutputStream(SAVE_FILENAME);
		ObjectOutputStream oos = new ObjectOutputStream(fos);

		oos.writeObject(pa);
		oos.writeObject(pb);
		oos.writeObject(pc);
		oos.close();
	}

	private void deserializePoints() throws IOException, ClassNotFoundException {
		FileInputStream fis = new FileInputStream(SAVE_FILENAME);
		ObjectInputStream ois = new ObjectInputStream(fis);

		pa = (Point)ois.readObject();
		pb = (Point)ois.readObject();
		pc = (Point)ois.readObject();

		ois.close();
	}

	private void printPoints() {
		PrintStream ps = System.out;

		ps.println(pa);
		ps.println(pb);
		ps.println(pc);
	}
}

KLASA "POINT"

import java .io.Serializable;

// serializacja obiektów - interfejs "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 + ")";
	}
}

Gdybyśmy czytali przepis "serializacja obiektów krok po kroku" brzmiałby mniej więcej tak:

  1. Utwórz obiekt, który ma być poddany serializacji danych.
  2. Zaimplementuj do niego interfejs "Serializable" w celu uprzedzenia kompilatora, że taki manewr ma być dopuszczony dla klasy. To jest specyficzny interfejs, który jedynie odblokowuje możliwość serializacji, a sam nie posiada żadnych metod do przesłonięcia!
  3. Dodaj specjalną właściwość do klasy o nazwie "serialVersionUID" typu "long" z modyfikatorami "private static final" jako stała statyczna (ARCYWAŻNY WPIS, szczegóły znajdują się w odrębnym artykule).
  4. Zdefiniuj funkcję serializującą obiekty dodając słowo kluczowe "throws", a w niej:
    1. zmienną typu "FileOutputStream" podając nazwę pliku do którego będą wrzucone dane
    2. zmienną typu "ObjectOutputStream" podając wcześniej utworzony obiekt
    3. wywołanie metody "writeObject" ze strumienia wyjściowego obiektów podając w nawiasy obiekt, który chcemy przechować
    4. wywołanie metody "close" zamykającej plik
  5. Zdefiniuj funkcję deserializującą (odczytującą) obiekty dodając słowo kluczowe "throws", a w niej:
    1. zmienną typu "FileInputStream" podając nazwę pliku z którego dane będą wyjmowane
    2. zmienną typu "ObjectInputStream" podając wcześniej utworzony obiekt
    3. przypisanie do każdego z obiektów wartości z wywoływanej metody "readObject" ZACHOWUJĄC TAKĄ SAMĄ KOLEJNOŚĆ i rzutując na odpowiednią klasę
    4. wywołanie metody "close" zamykającej plik
  6. Dodaj klauzulę "try-catch" przechwytującą wyjątki i zawrzyj odpowiednią metodę w zależności od tego, czy chcesz zapisać, czy odczytać z pliku. Serializacja obiektów korzysta z metod mogących zgłosić wyjątek. W przypadku zapisu, utwórz wpierw instancje obiektów, a potem wywołaj funkcję serializującą. W przypadku odczytu, nie twórz nowych kopii i wywołaj od razu funkcję deserializującą z przypisaniami do obiektów.
Serializacja obiektów w języku Java na wyjściu

Tak wyglądają "zmielone" dane składowe obiektów przechowujące wartości chronione przed edycją z zewnątrz.

Nie dostaliście oczopląsu? Mam taką nadzieję. Prościej się tego napisać już nie da, aby dało się to zaprogramować w obie strony. Serializacja obiektów ma ten duży plus, że zapobiega zewnętrznej edycji danych. Zostawiłem obrazek ukazujący jak wygląda plik z danymi przechowujący "zmielone" obiekty poddane serializacji.

Wyjaśniam wątpliwości. Wpis "pl.jasonxiii.serialization" odnosi się do nazwy pakietu do którego wrzuciłem wszystkie klasy. Nie jest tu uwzględniony, aby nie czynić całego kodu jeszcze odrobinę większego. Słowo kluczowe "throws" pozwala "przerzucić" odpowiedzialność przechwycenia wyjątku na metodę wywołującą, artykuł na ten temat został już opublikowany.


To wszystko na chwilę obecną, i tak zbyt poważnie to już wygląda.

PODOBNE ARTYKUŁY