Java Serialization 2013 — различия между версиями

Материал из SEWiki
Перейти к: навигация, поиск
(1. Serialization.java (основная часть))
(1. Serialization.java (основная часть))
Строка 329: Строка 329:
 
}
 
}
  
import java.io.Externalizable;
 
import java.io.FileInputStream;
 
import java.io.FileNotFoundException;
 
import java.io.FileOutputStream;
 
import java.io.IOException;
 
import java.io.InputStream;
 
import java.io.ObjectInput;
 
import java.io.ObjectInputStream;
 
import java.io.ObjectOutput;
 
import java.io.ObjectOutputStream;
 
import java.io.ObjectStreamField;
 
import java.io.OutputStream;
 
 
import java.io.Serializable;
 
import java.io.Serializable;
import java.util.ArrayList;
 
import java.util.List;
 
 
import org.junit.Test;
 
 
 
  
 
/**
 
/**
  * Лекция о сериализации в Java.
+
  * В простейшем случае достаточно добавить маркерный интерфейс implements
 +
* Serializable
 
  */
 
  */
@SuppressWarnings({"unused"})
+
@SuppressWarnings({ "serial"})
public class Serialization {
+
public class Point1 implements Serializable {
 +
double x;
 +
double y;
  
/****Введение****/
+
Point1(double x, double y) {
+
this.x = x;
/**
+
this.y = y;
*
+
* Сериализация -- запись объекта в байтовый поток.
+
*
+
* Десереализация -- CO.
+
*
+
* Все в пакете java.io
+
*
+
* Мотивация:
+
* 1. dump (ex. JavaBeans persistence)
+
* 2. RMI
+
*/
+
class Point {
+
double x;
+
double y;
+
 
}
 
}
 
  
 
 
//move to Point1.java and SimplePointTest.java
 
 
 
/****Процесс сериализации****/
 
 
/**
 
* В сериализации участвуют ВСЕ достижимые объекты.
 
*
 
* Запись:
 
* 1. Запись предка (если он сериализуем)
 
* 2. Запись полей (если они сериализуемы)
 
*
 
* Циклические зависимости корректно обрабатываются автоматически.
 
*
 
* Чтение:
 
* 1. Выделение памяти под объект
 
* 2. Чтение предка
 
* 3. Чтение полей
 
*/
 
 
/**
 
* Все поля должны быть сериализуемы!
 
*/
 
@SuppressWarnings("serial")
 
class Polygon implements Serializable {
 
 
List<Point3> vertices = new ArrayList<>();
 
 
}
 
 
 
/**
 
* Пока все просто, но впечатление обманчиво!
 
*
 
* 1. Внутреннее представление становится частью интерфейса
 
* Инкапсуляция летит к чертям!
 
* 2. Увеличивает объемы тестирования новых версий
 
* 3. Дополнительный конструктор!
 
* Необходимо обеспечивать все инварианты
 
* Некоторые дыры в безопасности
 
* 4. Все потомки становятся сериализуемыми!
 
*/
 
 
/****Управление сериализацией****/
 
 
/**
 
* Serial version UID (stream unique identifier)
 
*
 
* Применяется для обеспечения совместимости, когда версии класса изменяются
 
*
 
* По-умолчанию автоматически создается на основе имени, интерфейсов,
 
* public и protected полей
 
*
 
* В случае несовпадения -- InvalidClassException
 
*
 
*/
 
class Point2 implements Serializable {
 
private static final long serialVersionUID = 4889340678034881968L;
 
 
double x;
 
double y;
 
}
 
 
 
/**
 
* Модификатор transient.
 
* Исключает поле из процесса сериализации.
 
* Примеры:
 
* 1. Избыточная информация (предподсчитанные значения)
 
* 2. Несериализуемые поля
 
*
 
*/
 
class Point3 implements Serializable {
 
private static final long serialVersionUID = 4889340678034881968L;
 
 
double x;
 
double y;
 
transient int precomputedHash;
 
 
public int hashCode() {
 
return precomputedHash;
 
}
 
 
private int countHash() {
 
//some very involved procedure
 
return 0;
 
}
 
 
Point3(double x, double y) {
 
this.x = x;
 
this.y = y;
 
precomputedHash = countHash();
 
}
 
}
 
 
/**
 
* Настраиваемая сериализация
 
* Методы
 
* readObject(ObjectInputStream in) -- должен прочесть состояние из потока
 
* writeObject(ObjectOutputStream out) -- должен записать состояние в поток
 
*
 
* Процесс чтения
 
* 1. Выделение памяти
 
* 2. Вызов readObject
 
 
*/
 
class Point4 implements Serializable {
 
private static final long serialVersionUID = 4889340678034881968L;
 
 
double x;
 
double y;
 
 
transient int precomputedHash;
 
 
public int hashCode() {
 
return precomputedHash;
 
}
 
 
private int countHash() {
 
//some very involved procedure
 
return 0;
 
}
 
 
Point4(double x, double y) {
 
this.x = x;
 
this.y = y;
 
precomputedHash = countHash();
 
}
 
 
/*
 
* Отвечает только за запись полей ЭТОГО класса, не предка и не потомка!
 
*/
 
private void writeObject(ObjectOutputStream s) throws IOException {
 
/*
 
* Реализует стандартный механизм сериализации.
 
* Может вызываться только из writeObject, иначе NotActiveException
 
*/
 
s.defaultWriteObject();
 
}
 
 
//отвечает только за чтение полей ЭТОГО класса, не предка и не потомка!
 
private void readObject(ObjectInputStream s) throws IOException,
 
ClassNotFoundException {
 
/*
 
* Реализует стандартный механизм десериализации.
 
* Может вызываться только из readObject, иначе NotActiveException
 
*/
 
s.defaultReadObject();
 
//восстановление инвариантов
 
precomputedHash = countHash();
 
}
 
}
 
 
 
 
 
 
//move to Point5.java
 
 
 
 
 
 
 
/**
 
* Сериализация с несериализуемым предком.
 
*
 
* Если хочется отнаследовать сериализуемый класс от
 
* несериализуемого предка, то могут быть проблемы...
 
*
 
* Формальное требование одно -- предок должен иметь
 
* конструктор по-умолчанию.
 
*
 
* Но только ли?!
 
*/
 
class NonSerializablePoint {
 
private double x;
 
private double y;
 
 
protected double getX() {return x;}
 
 
protected double getY() {return y;}
 
 
protected void init(double x, double y) {
 
this.x = x;
 
this.y = y;
 
}
 
 
protected NonSerializablePoint() {}
 
 
public NonSerializablePoint(double x, double y) {
 
init(x, y);
 
}
 
}
 
 
// Serializable subclass of nonserializable stateful class
 
class ColoredPoint extends NonSerializablePoint implements Serializable {
 
private int color;
 
 
// Конструктор использует обычный механизм
 
public ColoredPoint(double x, double y, int color) {
 
super(x, y);
 
this.color = color;
 
}
 
 
private void readObject(ObjectInputStream s) throws IOException,
 
ClassNotFoundException {
 
s.defaultReadObject();
 
// Manually deserialize and initialize superclass state
 
double x = s.readDouble();
 
double y = s.readDouble();
 
init(x, y);
 
}
 
 
private void writeObject(ObjectOutputStream s) throws IOException {
 
s.defaultWriteObject();
 
// Manually serialize superclass state
 
s.writeDouble(getX());
 
s.writeDouble(getY());
 
}
 
 
private static final long serialVersionUID = 1856835860954L;
 
}
 
 
 
 
/**
 
* Externalizable
 
*
 
* Сериализация "в ручную"
 
 
* void readExternal(ObjectInput in)
 
* void writeExternal(ObjectOutput out)
 
*
 
* Должен быть конструктор по-умолчанию
 
*
 
* Чтение: вызов конструктора по-умолчанию, вызов readExternal
 
*/
 
class Point6 implements Externalizable {
 
private double x;
 
private double y;
 
 
Point6(double x, double y) {
 
this.x = x;
 
this.y = y;
 
}
 
 
@Override
 
public void writeExternal(ObjectOutput out) throws IOException {
 
out.writeDouble(x);
 
out.writeDouble(y);
 
}
 
@Override
 
public void readExternal(ObjectInput in) throws IOException,
 
ClassNotFoundException {
 
this.x = in.readDouble();
 
this.y = in.readDouble();
 
}
 
}
 
 
/**
 
* "Подмена" сериализуемого объекта.
 
*
 
* Когда вместо самого объекта сериализуется его альтернативное представление
 
* в виде другого объекта некоторого (возможно того же самого) сериализуемого класса.
 
*
 
* Object writeReplace() -- какой объект записать вместо данного
 
* Object readResolve() -- какой объект восстановить вместо прочитанного
 
*
 
* Реализуются у разных классов!!!
 
*/
 
 
 
}
 
}
 
</source>
 
</source>

Версия 15:09, 22 мая 2013

Что почитать

1. Serialization.java (основная часть)

import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;



/**
 * Лекция о сериализации в Java.
 */
@SuppressWarnings({"unused"})
public class Serialization {

	/****Введение****/
	
	/**
	 * 
	 * Сериализация -- запись объекта в байтовый поток.
	 * 
	 * Десереализация -- CO.
	 * 
	 * Все в пакете java.io
	 * 
	 * Мотивация:
	 * 	1. dump (ex. JavaBeans persistence)
	 * 	2. RMI
	 */
	class Point {
		double x;
		double y;
	}
	

	
	
	//move to Point1.java and SimplePointTest.java
	
	
	/****Процесс сериализации****/
	
	/**
	 * В сериализации участвуют ВСЕ достижимые объекты.
	 * 
	 * Запись:
	 * 	1. Запись предка (если он сериализуем)
	 * 	2. Запись полей (если они сериализуемы)
	 * 
	 * Циклические зависимости корректно обрабатываются автоматически.
	 * 
	 * Чтение:
	 * 	1. Выделение памяти под объект
	 * 	2. Чтение предка
	 * 	3. Чтение полей
	 */
	
	/**
	 * Все поля должны быть сериализуемы!
	 */
	@SuppressWarnings("serial")
	class Polygon implements Serializable {

		List<Point3> vertices = new ArrayList<>();
		
	}
	
	
	/**
	 * Пока все просто, но впечатление обманчиво!
	 * 
	 * 1. Внутреннее представление становится частью интерфейса
	 * 		Инкапсуляция летит к чертям!
	 * 2. Увеличивает объемы тестирования новых версий
	 * 3. Дополнительный конструктор! 
	 * 		Необходимо обеспечивать все инварианты
	 * 		Некоторые дыры в безопасности
	 * 4. Все потомки становятся сериализуемыми!
	 */
	
	/****Управление сериализацией****/
	
	/**
	 * Serial version UID (stream unique identifier)
	 * 
	 * Применяется для обеспечения совместимости, когда версии класса изменяются
	 * 
	 * По-умолчанию автоматически создается на основе имени, интерфейсов, 
	 * public и protected полей
	 * 
	 * В случае несовпадения -- InvalidClassException
	 * 
	 */
	class Point2 implements Serializable {
		private static final long serialVersionUID = 4889340678034881968L;

		double x;
		double y;
	}


	/**
	 * Модификатор transient.
	 * Исключает поле из процесса сериализации.
	 * Примеры:
	 * 	1. Избыточная информация (предподсчитанные значения)
	 * 	2. Несериализуемые поля
	 * 
	 */
	class Point3 implements Serializable {
		private static final long serialVersionUID = 4889340678034881968L;

		double x;
		double y;
		transient int precomputedHash;
		
		public int hashCode() {
			return precomputedHash;
		}
		
		private int countHash() {
			//some very involved procedure
			return 0;
		}
		
		Point3(double x, double y) {
			this.x = x;
			this.y = y;
			precomputedHash = countHash();
		}
	}
	
	/**
	 * Настраиваемая сериализация 
	 * Методы 
	 * 	readObject(ObjectInputStream in) -- должен прочесть состояние из потока 
	 * 	writeObject(ObjectOutputStream out) -- должен записать состояние в поток
	 * 
	 * Процесс чтения
	 * 	1. Выделение памяти
	 * 	2. Вызов readObject
	 *  
	 */
	class Point4 implements Serializable {
		private static final long serialVersionUID = 4889340678034881968L;

		double x;
		double y;
		
		transient int precomputedHash;
		
		public int hashCode() {
			return precomputedHash;
		}
		
		private int countHash() {
			//some very involved procedure
			return 0;
		}
		
		Point4(double x, double y) {
			this.x = x;
			this.y = y;
			precomputedHash = countHash();
		}
		
		/*
		 * Отвечает только за запись полей ЭТОГО класса, не предка и не потомка!
		 */
		private void writeObject(ObjectOutputStream s) throws IOException {
			/*
			 * Реализует стандартный механизм сериализации.
			 * Может вызываться только из writeObject, иначе NotActiveException
			 */
			s.defaultWriteObject();
		}

		//отвечает только за чтение полей ЭТОГО класса, не предка и не потомка!
		private void readObject(ObjectInputStream s) throws IOException,
				ClassNotFoundException {
			/*
			 * Реализует стандартный механизм десериализации.
			 * Может вызываться только из readObject, иначе NotActiveException
			 */
			s.defaultReadObject();
			//восстановление инвариантов
			precomputedHash = countHash();
		}
	}


	
	
	
	//move to Point5.java
	
	
	
	
	
	
	/**
	 * Сериализация с несериализуемым предком.
	 * 
	 * Если хочется отнаследовать сериализуемый класс от 
	 * несериализуемого предка, то могут быть проблемы...
	 * 
	 * Формальное требование одно -- предок должен иметь 
	 * конструктор по-умолчанию.
	 * 
	 * Но только ли?!
	 */
	class NonSerializablePoint {
		private double x;
		private double y;
		
		protected double getX() {return x;}
		
		protected double getY() {return y;}
		
		protected void init(double x, double y) {
			this.x = x;
			this.y = y;
		}
		
		protected NonSerializablePoint() {}
		
		public NonSerializablePoint(double x, double y) {
			init(x, y);
		}
	}
	
	// Serializable subclass of nonserializable stateful class
	class ColoredPoint extends NonSerializablePoint implements Serializable {
		private int color;

		// Конструктор использует обычный механизм
		public ColoredPoint(double x, double y, int color) {
			super(x, y);
			this.color = color;
		}
		
		private void readObject(ObjectInputStream s) throws IOException,
				ClassNotFoundException {
			s.defaultReadObject();
			// Manually deserialize and initialize superclass state
			double x = s.readDouble();
			double y = s.readDouble();
			init(x, y);
		}
		
		private void writeObject(ObjectOutputStream s) throws IOException {
			s.defaultWriteObject();
			// Manually serialize superclass state
			s.writeDouble(getX());
			s.writeDouble(getY());
		}

		private static final long serialVersionUID = 1856835860954L;
	}

	
	
	/**
	 * Externalizable
	 * 
	 * Сериализация "в ручную"
	 *  
	 * 	void readExternal(ObjectInput in)
	 * 	void writeExternal(ObjectOutput out) 
	 * 
	 * Должен быть конструктор по-умолчанию
	 * 
	 * Чтение: вызов конструктора по-умолчанию, вызов readExternal
	 */
	class Point6 implements Externalizable {
		private double x;
		private double y;

		Point6(double x, double y) {
			this.x = x;
			this.y = y;
		}
		
		@Override
		public void writeExternal(ObjectOutput out) throws IOException {
			out.writeDouble(x);
			out.writeDouble(y);
		}
		@Override
		public void readExternal(ObjectInput in) throws IOException,
				ClassNotFoundException {
			this.x = in.readDouble();
			this.y = in.readDouble();
		}
	}
	
	/**
	 * "Подмена" сериализуемого объекта.
	 * 
	 * Когда вместо самого объекта сериализуется его альтернативное представление
	 * в виде другого объекта некоторого (возможно того же самого) сериализуемого класса. 
	 * 
	 * Object writeReplace() -- какой объект записать вместо данного
	 * Object readResolve() -- какой объект восстановить вместо прочитанного
	 * 
	 * Реализуются у разных классов!!!
	 */
	
}

import java.io.Serializable;

/**
 * В простейшем случае достаточно добавить маркерный интерфейс implements
 * Serializable
 */
@SuppressWarnings({ "serial"})
public class Point1 implements Serializable {
	double x;
	double y;

	Point1(double x, double y) {
		this.x = x;
		this.y = y;
	}

}