Pure Java – 60 File and I/O – 05 – Serialization

Merhaba Arkadaslar,
Bu bolumde Javada Serialization(Serilestirme) konusundan bahsedecegim. Bu sayede 2 yeni File IO sinifi gorecegiz ;
java.io.ObjectOutputStream
java.io.ObjectInputStream

Serialization(Serilestirme) , “bu objeyi instance variable’lariyla birlikte kaydet(save)” anlamina gelmektedir. Bu durumda ilgili sinifin Serializable olmasi gereklidir. java.io.Serializable bir arabirimdir(interface).

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Dog implements Serializable {
	String name = "Karabas";
}

public class SerializeDog {

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		Dog dog = new Dog();

		FileOutputStream fos = new FileOutputStream("dog.serial");
		ObjectOutputStream oos = new ObjectOutputStream(fos);

		oos.writeObject(dog);
		oos.flush();
		oos.close();
		
		FileInputStream fis = new FileInputStream("dog.serial");
		ObjectInputStream ois = new ObjectInputStream(fis);		
		
		Dog deserializedDog = (Dog)ois.readObject();
		System.out.println(deserializedDog.name);
		
		ois.close();
		
	}
}

Adim adim inceleyelim ;
Dog isminde bir sinif tanimi yaptik,Dog sinifimiz Serializable interface/arabirimini uygulamaktadir. (implements)

Daha sonrasinda FileOutputStream sinifindan yararlaniyoruz burada dosya uzantisi .serial olmak zorunda degil. Siz istediginiz degeri verebilirsiniz.

Burada dikkat etmemiz gereken yeni gordugumuz ObjectOutputStream sinifidir. ObjectOutputStream sinifi bize writeObject metodunu saglamaktadir. Bu metoda arguman olarak Serializable bir sinif objesi verebiliriz. Bu islem sonrasi artik bizim dog objemiz instance degiskenleri ile birlikte “dog.serial” dosyasina kayit edildi.

Dosyamiz vasitasiyla objemizi geri olusturmak icin(deserialized) icin FileInputStream ve ObjectInputStream siniflarindan yararlaniyoruz. ObjectInputStream sinifinda yer alan readObject metodu Object tipinde bir donuse sahiptir. Burada (Dog) tipine reference downcasting yapiyoruz.Burada objemiz Dog tipine cast edilebildigi icin calisma zamaninda herhangi bir sorun cikmayacaktir , cunku serialized/serilestirdigimiz objemizin tipi Dog deserialized etmeye calistigimiz objenin tipi de Dog.

Unutmayalim soz konusu Serialization ilgili sinif bu arabimi uygulamalidir. Eger uygulamazsa derleme hatasi vermez fakat calisma zamaninda su hatayi(exception) verecektir.

java.io.NotSerializableException

Eger HAS-A iliskisi varsa bu durumda iki sinifi da Serializable yapmamiz gereklidir;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Keyboard implements Serializable {
	int size;
	String color;

	public Keyboard(int size, String color) {
		super();
		this.size = size;
		this.color = color;
	}
}

class Laptop implements Serializable {
	Keyboard key = new Keyboard(3, "black");
	int price = 5000;
}

public class LaptopTest {
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		Laptop laptop = new Laptop();

		FileOutputStream fos = new FileOutputStream("laptop.ser");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(laptop);
		oos.flush();
		oos.close();

		FileInputStream fis = new FileInputStream("laptop.ser");
		ObjectInputStream ois = new ObjectInputStream(fis);

		Laptop deserializedLaptop = (Laptop) ois.readObject();
		System.out.println(deserializedLaptop.price);
		System.out.println(deserializedLaptop.key.color);
		System.out.println(deserializedLaptop.key.size);

		ois.close();
	}
}

Burada Laptop HAS-A Keyboard iliskisi vardir. Hatirlayacagimiz gibi bir sinif bir baska sinif tipinde referans degiskene sahipse bu iliskiye HAS-A iliskisi diyorduk.

Bu ornegimizde Laptop sinifina ait bir objeyi serilestirmek istiyoruz. Eger Keyboard sinifi tipindeki degiskenimiz null olarak birakilirsa Keyboard sinifini Serializable yapmaya gerek yok fakat burada oldugu gibi kullanilacaksa bu durumda Serializable olmak zorundadir. Aksi durumda calisma zamaninda NotSerializableException hatasi/exception verecektir.

Simdi ise farkli bir durumdan bahsedelim Keyboard sinifimiz Serializable degil ve Laptop HAS-A Keyboard iliskisi soz konusu.Biz Laptop objesini serilestirmek istiyoruz bu durumda ne yapmaliyiz ?

Keyboard referans degiskenimiz icin transient anahtar kelimesini kullaniriz . Serialization isleminde transient olarak tanimlanan instance variable isleme tabi tutulmaz atlanir.

Biraz onceki ornegimizdeki ilgili kismi su sekilde degistirelim ve tekrar calistiralim ;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Keyboard {
	int size;
	String color;

	public Keyboard(int size, String color) {
		super();
		this.size = size;
		this.color = color;
	}
}

class Laptop implements Serializable {
	transient Keyboard key = new Keyboard(3, "black");
	int price = 5000;
}

public class LaptopTest {
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		Laptop laptop = new Laptop();

		FileOutputStream fos = new FileOutputStream("laptop.ser");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(laptop);
		oos.flush();
		oos.close();

		FileInputStream fis = new FileInputStream("laptop.ser");
		ObjectInputStream ois = new ObjectInputStream(fis);

		Laptop deserializedLaptop = (Laptop) ois.readObject();
		System.out.println(deserializedLaptop.price);
		// System.out.println(deserializedLaptop.key.color); // key null
		// olacaktir
		// System.out.println(deserializedLaptop.key.size); // key null
		// olacaktir

		ois.close();
	}
}

Laptop objemizi serilestiriyoruz fakat Keyboard referans degiskenimiz transient oldugu icin serilestirme isleminde atlaniyor. Deserialized isleminde ise null degerine sahip olur. Peki null degerden baska bir degere sahip olmasini nasil saglariz ? Bunun icin kullandigimiz writeObject ve readObject metotlarini kendimiz yazmamiz gerekmektedir ;

	private void writeObject(ObjectOutputStream os) {

	}

	private void readObject(ObjectInputStream is) {

	}

Bu metotlar Serialization ve Deserialization islemlerinde otomatik olarak calisacaktir.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Keyboard {
	int size;
	String color;

	public Keyboard(int size, String color) {
		super();
		this.size = size;
		this.color = color;
	}
}

class Laptop implements Serializable {
	transient Keyboard key = null;
	int price = 5000;

	private void writeObject(ObjectOutputStream os) throws IOException {
		os.defaultWriteObject();
		os.writeInt(3);
		os.writeUTF("black");

		// burada eklenme sirasi onemlidir.
	}

	private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException {
		is.defaultReadObject();
		key = new Keyboard(is.readInt(), is.readUTF());
	}
}

public class LaptopTest {
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		Laptop laptop = new Laptop();

		FileOutputStream fos = new FileOutputStream("laptop.ser");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(laptop);
		oos.flush();
		oos.close();

		FileInputStream fis = new FileInputStream("laptop.ser");
		ObjectInputStream ois = new ObjectInputStream(fis);

		Laptop deserializedLaptop = (Laptop) ois.readObject();
		System.out.println(deserializedLaptop.price);
		System.out.println(deserializedLaptop.key.color);
		System.out.println(deserializedLaptop.key.size);
		ois.close();
	}
}

Laptop HAS-A Keyboard durumu var.Burada dikkat edecek olursak Keyboard sinifi Serializable olarak tanimli degildir. Bu durumda Keyboard referans degiskeni transient olarak tanimlanmalidir boylelikle serilestirme isleminde atlanacaktir ve null degere sahip olacaktir.

Burada Laptop sinifi icerisinde writeObject ve readObject metotlarini kullanarak defaultWriteObject ve defaultReadObject metotlari yardimi ile diledigimiz degerleri uygun sekilde atayabiliriz ve okuyabiliriz(read). (Burada ekleme sirasi ve yapilandiricilara dikkat etmek gerekli)

Serialization islemi sirasinda otomatik olarak writeObject calisir , deserialization islemi sirasinda otomatik olarak readObject metodu cagrilir.
Kisacasi manuel olarak objemizin state/durumu/instance degiskenlerini yazmak/okumak icin writeObject ve readObject metotlarini kullaniriz.

Hatirlayacagimiz gibi bir obje olusturdugumuzda yapilandirici calisir. Fakat deserialized isleminde yapilandirici calismaz. Instance degiskenler icin initialze islemi tekrar yapilmaz. Serilestirme islemi sirasinda hangi degerleri verdiysek o degerler geri getirilecektir. Tabi transient olan instance variablelar null, 0 gibi default degerlere sahip olacaktir.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Foo implements Serializable {
	int num = 3;

	Foo() {
		num = 20;
	}

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		FileOutputStream fos = new FileOutputStream("foo.ser");
		ObjectOutputStream oos = new ObjectOutputStream(fos);

		Foo foo = new Foo();
		foo.num = 50;

		oos.writeObject(foo);
		oos.flush();
		oos.close();

		FileInputStream fis = new FileInputStream("foo.ser");
		ObjectInputStream ois = new ObjectInputStream(fis);

		Foo deserializedFoo = (Foo) ois.readObject();
		System.out.println(deserializedFoo.num);
		// deserialize islemi sirasinda yapilandiri calismaz !
		// deserialize islemi sirasinda instance degiskenler icin initalize
		// islemi tekrar calismaz !
		// num degiskeni 50 degerine sahipti bu sekilde serilestirilmisti.

		ois.close();
	}

}

Simdi bir diger ornegi gorelim ;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Animal {
	int height = 30;
}

public class Dog extends Animal implements Serializable {
	String name;

	public Dog(int height, String name) {
		this.height = height;
		this.name = name;
	}

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		FileOutputStream fos = new FileOutputStream("dog.ser");
		ObjectOutputStream oos = new ObjectOutputStream(fos);

		Dog dog = new Dog(50, "karabas");

		System.out.println(dog.height);
		System.out.println(dog.name);

		oos.writeObject(dog);
		oos.close();

		FileInputStream fis = new FileInputStream("dog.ser");
		ObjectInputStream ois = new ObjectInputStream(fis);

		Dog deserializedDog = (Dog) ois.readObject();

		System.out.println(deserializedDog.height);
		System.out.println(deserializedDog.name);

		ois.close();
	}

}

Dog sinifimiz Animal sinifini kalitmaktadir. Dog sinifi Serializable olmasina ragmen Animal sinifi Serializable degildir.

Hatirlayacagimiz gibi Deserialized islemi sirasinda yapilandiricilar ve instance degiskenlere deger atanmasi yapilmayacaktir. Fakat burada Animal sinifi Serializable degildir. Deserialized islemi sirasinda , Serializable olmayan siniflarin yapilandiricilari ve instance degiskenlere deger atanmasi yapilir.

Yani burada Dog sinifinin yapilandiricisi deserialized isleminde calismaz, Animal sinifindaki instance degiskenin initialize islemi ise deserialized islemi sirasinda caliscaktir.

Collection veya array tipinde instance degiskenleri serilestirmeye calistigimizda , her eleman Serializable ozellige sahip olmalidir.

Static degiskenlerin Serialization islemleri sirasinda kullanilmasi onerilmez. Hatirlayacagimiz gibi static degiskenler sinifa aittir, instance degiskenler objeye aittir.

Yazimi burada sonlandiriyorum.
Herkese Bol Javali Gunler dilerim.
Be an oracle man , import java.*;
Levent Erguder
OCP, Java SE 6 Programmer
OCE, Java EE 6 Web Component Developer

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *