Яка різниця між Serializable
і Externalizable
на Java?
Яка різниця між Serializable
і Externalizable
на Java?
Відповіді:
Щоб додати до інших відповідей, реалізуючи java.io.Serializable
, ви отримуєте "автоматичну" можливість серіалізації для об'єктів вашого класу. Не потрібно реалізовувати будь-яку іншу логіку, вона просто спрацює. Час виконання Java використовуватиме роздуми, щоб визначити, як маршалити та не маршалювати об’єкти.
У попередній версії Java рефлексія була дуже повільною, і тому серіалізація великих об’єктних графіків (наприклад, у програмах RMI клієнт-сервер) була проблемою з продуктивністю. Щоб вирішити цю ситуацію, java.io.Externalizable
був наданий інтерфейс, який, як java.io.Serializable
і з написаними на замовлення механізмами для виконання функцій маршалінгу та демарширування (потрібно реалізувати readExternal
та writeExternal
методи у своєму класі). Це дає вам можливість подолати вузьке вузьке місце.
В останніх версіях Java (на 1.3, безумовно) ефективність відображення набагато краща, ніж раніше, і тому це набагато менше проблем. Я підозрюю, що Externalizable
з сучасним JVM вам буде важко отримати значну користь .
Крім того, вбудований механізм серіалізації Java не єдиний, ви можете отримати сторонні заміни, такі як JBoss Serialization, що значно швидше, і є заміною за замовчуванням.
Великий недолік Externalizable
полягає в тому, що ви повинні самостійно підтримувати цю логіку - якщо ви додаєте, видаляєте або змінюєте поле у своєму класі, ви повинні змінити свої writeExternal
/ readExternal
методи, щоб їх врахувати.
Підсумовуючи, Externalizable
це реліквія Яви 1,1 днів. У цьому насправді більше немає потреби.
Externalizable
допомагає багато .
Externalizable
мені підходить набагато краще, оскільки я не хочу виводити масиви з порожніми пробілами або об'єктами заповнення, а також із явним інтерфейсом ви можете обробляти спадщину, що означає, що мій синхронізований підрозділ -клас може легко додати блокування навколо виклику writeExternal()
. Так що так, Externalizable все ще дуже актуальний, звичайно, для великих або складних об'єктів.
Серіалізація забезпечує функціональність за замовчуванням для зберігання та подальшого відтворення об’єкта. Він використовує багатослівний формат для визначення цілого графа об'єктів, що підлягають збереженню, наприклад, припустимо, що у вас є linkedList і ви кодуєте, як показано нижче, тоді серіалізація за замовчуванням виявить усі об'єкти, які пов’язані між собою, і серіалізується. При серіалізації за замовчуванням об'єкт будується повністю з його збережених бітів, без викликів конструктора.
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Users/Desktop/files/temp.txt"));
oos.writeObject(linkedListHead); //writing head of linked list
oos.close();
Але якщо ви хочете обмежувати серіалізацію або не хочете, щоб певна частина вашого об'єкта була серіалізована, тоді використовуйте Externalizable. Інтерфейс Externalizable розширює інтерфейс Serializable і додає два методи, writeExternal () і readExternal (). Вони автоматично викликаються під час серіалізації або десеріалізації. Працюючи з Externalizable, ми повинні пам’ятати, що конструктор за замовчуванням повинен бути загальнодоступним, оскільки код викине виключення. Будь ласка, дотримуйтесь наведеного нижче коду:
public class MyExternalizable implements Externalizable
{
private String userName;
private String passWord;
private Integer roll;
public MyExternalizable()
{
}
public MyExternalizable(String userName, String passWord, Integer roll)
{
this.userName = userName;
this.passWord = passWord;
this.roll = roll;
}
@Override
public void writeExternal(ObjectOutput oo) throws IOException
{
oo.writeObject(userName);
oo.writeObject(roll);
}
@Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException
{
userName = (String)oi.readObject();
roll = (Integer)oi.readObject();
}
public String toString()
{
StringBuilder b = new StringBuilder();
b.append("userName: ");
b.append(userName);
b.append(" passWord: ");
b.append(passWord);
b.append(" roll: ");
b.append(roll);
return b.toString();
}
public static void main(String[] args)
{
try
{
MyExternalizable m = new MyExternalizable("nikki", "student001", 20);
System.out.println(m.toString());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/Desktop/files/temp1.txt"));
oos.writeObject(m);
oos.close();
System.out.println("***********************************************************************");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/Desktop/files/temp1.txt"));
MyExternalizable mm = (MyExternalizable)ois.readObject();
mm.toString();
System.out.println(mm.toString());
}
catch (ClassNotFoundException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
catch(IOException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Тут, якщо ви прокоментуєте конструктор за замовчуванням, код буде занижувати нижче виключення:
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
Ми можемо зауважити, що як пароль є конфіденційною інформацією, тому я не серіалізую її методом writeExternal (ObjectOutput oo) і не встановлюю значення того ж у readExternal (ObjectInput oi). Це гнучкість, яку надає Externalizable.
Вихід вищевказаного коду наведено нижче:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
Ми можемо спостерігати, як ми не встановлюємо значення passWord, тому воно є нульовим.
Те ж можна досягти, оголосивши поле паролем перехідним.
private transient String passWord;
Сподіваюся, це допомагає. Прошу вибачення, якщо я допустив помилки. Дякую.
Основні відмінності між Serializable
таExternalizable
Serializable
це інтерфейс маркера без будь-яких методів. Externalizable
інтерфейс містить два способи: writeExternal()
і readExternal()
.Serializable
інтерфейс. Процес серіалізації, визначений програмістом, стартує для Externalizable
інтерфейсів класів, що реалізують .Externalizable
інтерфейсом. Ви можете підтримувати різні версії вашого об’єкта. Якщо ви реалізуєте Externalizable
, це ваша відповідальність за серіалізацію super
класуSerializable
використовує відображення для побудови об'єкта і не вимагає конструктора аргументів. Але Externalizable
вимагає публічного конструктора без аргументів.Зверніться до блогу шляхом Hitesh Garg
для отримання більш докладної інформації.
Серіалізація використовує певні поведінки за замовчуванням для зберігання та подальшого відтворення об'єкта. Ви можете вказати, в якому порядку чи як обробляти посилання та складні структури даних, але з часом це зводиться до використання поведінки за замовчуванням для кожного примітивного поля даних.
Екстерналізація використовується в тих рідкісних випадках, коли ви дійсно хочете зберігати і перебудовувати свій об'єкт зовсім іншим способом і без використання механізмів серіалізації за замовчуванням для полів даних. Наприклад, уявіть, що у вас була своя унікальна схема кодування та стиснення.
Об'єктна серіалізація використовує інтерфейси Serializable та Externalizable. Об'єкт Java лише серіалізаційний. якщо клас або будь-який його суперкласс реалізує або java.io.Serializable інтерфейс, або його підінтерфейс, java.io.Externalizable. Більшість класів java є серіалізаційними .
NotSerializableException
: packageName.ClassName
«Для участі в об'єкті класу в процесі серіалізації, клас повинен реалізовувати інтерфейс Serializable або Externalizable.Об'єктна серіалізація створює потік з інформацією про класи Java для об'єктів, які зберігаються. Для об'єктів, що серіалізуються, зберігається достатня інформація для відновлення цих об'єктів, навіть якщо є інша (але сумісна) версія реалізації класу. Інтерфейс Serializable визначений для ідентифікації класів, які реалізують протокол серіалізації:
package java.io;
public interface Serializable {};
InvalidClassException
«У процесі десеріалізації, якщо значення serialVersionUID локального класу відрізняється від відповідного класу відправника. то результат в конфлікті як
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
Для об'єктів Externalizable контейнер зберігає лише ідентифікацію класу об'єкта; клас повинен зберігати та відновлювати вміст. Інтерфейс Externalizable визначається наступним чином:
package java.io;
public interface Externalizable extends Serializable
{
public void writeExternal(ObjectOutput out)
throws IOException;
public void readExternal(ObjectInput in)
throws IOException, java.lang.ClassNotFoundException;
}
OptionalDataException
«Поля ОБОВ'ЯЗКОВО бути в одному порядку і типі, як ми їх виписали. Якщо в потоці є якесь невідповідність типу, він викидає OptionalDataException.
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
Поля примірника класу, який написав (виставив), щоб ObjectOutput
отримати серіалізацію.
Приклад « реалізує Serializable
class Role {
String role;
}
class User extends Role implements Serializable {
private static final long serialVersionUID = 5081877L;
Integer id;
Address address;
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
}
class Address implements Serializable {
private static final long serialVersionUID = 5081877L;
String country;
}
Приклад « реалізує Externalizable
class User extends Role implements Externalizable {
Integer id;
Address address;
// mandatory public no-arg constructor
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
}
Приклад
public class CustomClass_Serialization {
static String serFilename = "D:/serializable_CustomClass.ser";
public static void main(String[] args) throws IOException {
Address add = new Address();
add.country = "IND";
User obj = new User("SE");
obj.id = 7;
obj.address = add;
// Serialization
objects_serialize(obj, serFilename);
objects_deserialize(obj, serFilename);
// Externalization
objects_WriteRead_External(obj, serFilename);
}
public static void objects_serialize( User obj, String serFilename ) throws IOException{
FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
// java.io.NotSerializableException: com.github.objects.Address
objectOut.writeObject( obj );
objectOut.flush();
objectOut.close();
fos.close();
System.out.println("Data Stored in to a file");
}
public static void objects_deserialize( User obj, String serFilename ) throws IOException{
try {
FileInputStream fis = new FileInputStream( new File( serFilename ) );
ObjectInputStream ois = new ObjectInputStream( fis );
Object readObject;
readObject = ois.readObject();
String calssName = readObject.getClass().getName();
System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException
User user = (User) readObject;
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void objects_WriteRead_External( User obj, String serFilename ) throws IOException {
FileOutputStream fos = new FileOutputStream(new File( serFilename ));
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
obj.writeExternal( objectOut );
objectOut.flush();
fos.close();
System.out.println("Data Stored in to a file");
try {
// create a new instance and read the assign the contents from stream.
User user = new User();
FileInputStream fis = new FileInputStream(new File( serFilename ));
ObjectInputStream ois = new ObjectInputStream( fis );
user.readExternal(ois);
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@побачити
Інтерфейс Externalizable насправді не був забезпечений для оптимізації продуктивності процесу серіалізації! але забезпечити засоби реалізації власної власної обробки та запропонувати повний контроль над форматом та вмістом потоку для об’єкта та його супер типів!
Прикладами цього є реалізація видалення AMF (ActionScript Format Format) для передачі власних об'єктів сценарію дії через мережу.
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
Серіалізація за замовчуванням дещо багатослівна і передбачає максимально широкий сценарій використання серіалізованого об'єкта, і відповідно формат за замовчуванням (Serializable) анотує результат, що виходить, з інформацією про клас серіалізованого об'єкта.
Екстерналізація дає виробнику об'єктного потоку повний контроль над точними метаданими класу (якщо такі є) за межами мінімально необхідної ідентифікації класу (наприклад, його назви). Це явно бажано в певних ситуаціях, наприклад, у закритих середовищах, коли виробник потоку об'єктів та його споживач (який відводить об'єкт із потоку) узгоджуються, а додаткові метадані про клас не служать ніякій меті та погіршують продуктивність.
Додатково (як зазначає Урі) екстерналізація також забезпечує повний контроль над кодуванням даних у потоці, що відповідає типам Java. Для (надуманого) прикладу, ви можете записати булеве значення true як "Y", а false як "N". Екстерналізація дозволяє це зробити.
Розглядаючи варіанти для підвищення продуктивності, не забувайте про власну серіалізацію. Ви можете дозволити Java робити те, що робить добре, або, принаймні, досить добре, безкоштовно , і надавати власну підтримку для того, що робить погано. Зазвичай це набагато менше коду, ніж повна підтримка Externalizable.
Існує так багато різниці між Serializable та Externalizable, але коли ми порівнюємо різницю між власною Serializable (переосмислений writeObject () & readObject ()) та Externalizable, то ми виявляємо, що власна реалізація тісно пов'язана з класом ObjectOutputStream, де, як у випадку Externalizable, ми самі забезпечити реалізацію ObjectOutput, який може бути класом ObjectOutputStream, або це може бути якийсь інший, як org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream
У випадку інтерфейсу Externalizable
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(key);
out.writeUTF(value);
out.writeObject(emp);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.key = in.readUTF();
this.value = in.readUTF();
this.emp = (Employee) in.readObject();
}
**In case of Serializable interface**
/*
We can comment below two method and use default serialization process as well
Sequence of class attributes in read and write methods MUST BE same.
// below will not work it will not work .
// Exception = java.io.StreamCorruptedException: invalid type code: 00\
private void writeObject(java.io.ObjectOutput stream)
*/
private void writeObject(java.io.ObjectOutputStream Outstream)
throws IOException {
System.out.println("from writeObject()");
/* We can define custom validation or business rules inside read/write methods.
This way our validation methods will be automatically
called by JVM, immediately after default serialization
and deserialization process
happens.
checkTestInfo();
*/
stream.writeUTF(name);
stream.writeInt(age);
stream.writeObject(salary);
stream.writeObject(address);
}
private void readObject(java.io.ObjectInputStream Instream)
throws IOException, ClassNotFoundException {
System.out.println("from readObject()");
name = (String) stream.readUTF();
age = stream.readInt();
salary = (BigDecimal) stream.readObject();
address = (Address) stream.readObject();
// validateTestInfo();
}
Я додав зразок коду, щоб пояснити краще. будь ласка, зареєструйте / вимкніть об'єктний випадок Externalizable. Вони не пов'язані ні з якою реалізацією безпосередньо.
Де Outstream / Instream тісно пов'язані з класами. Ми можемо розширити ObjectOutputStream / ObjectInputStream, але це буде трохи важко у використанні.
По суті, Serializable
це маркерний інтерфейс, який передбачає, що клас безпечний для серіалізації і JVM визначає, як він серіалізується. Externalizable
містить 2 способи readExternal
та writeExternal
. Externalizable
дозволяє реалізатору вирішити, як об’єкт серіалізується, де як Serializable
серіалізує об'єкти за замовчуванням.
Деякі відмінності:
Для серіалізації немає необхідності конструктора за замовчуванням цього класу, тому що Object тому, що JVM створює те саме за допомогою Reflection API. У разі екстерналізації кондуктора без аргументу не потрібно, оскільки управління знаходиться в руці програміста, а пізніше призначається десеріалізовані дані об'єкту через сетери.
При серіалізації, якщо користувач хоче пропустити певні властивості для серіалізації, він повинен позначати ці властивості як перехідні, навпаки, для екстерналізації не потрібно.
Якщо очікується підтримка зворотної сумісності для будь-якого класу, тоді рекомендується перейти з Externalizable. Серіалізація підтримує defaultObject, що зберігається, і якщо структура об'єкта порушена, це спричинить проблему під час десеріалізації.