Бесплатный курс по Java: от основ до продвинутого уровня
Контроль совместимости классов в Java с помощью SerialVersionUID
У каждого сериализуемого класса (именно класса, не объекта класса) есть полеSerialVersionUID.
Это числовой идентификатор, который меняется при каждом изменении класса.
Это может быть использовано при сериализации и десериализации.
Допустим у нас есть Serializable класс, объект которого мы сериализовали, а потом а потом в классе этого объекта сделали изменения, и соответственно, изменяется SerialVersionUID класса, и ясное дело десериализовать в объект измененного класса уже не получиться, выйдет ошибка. Чтобы этого избежать можно в сериализуемый класс добавить постоянное статическое значение поля SerialVersionUID, тогда десериализация не выбросит ошибку.
Ясное дело, десериализация будет работать только с полями, которые присутствуют в измененной версии класса, а те поля, которые были в версии класса при сериализации считаться не смогут.
Всё это нужно, чтобы была возможность какое-то время десериализовать класс, который постоянно изменяется.
Давайте, для начала, сериализуем объект класса у которого SerialVersionUID имеет статическое значение.
Пример программы:
import java.io.*;
import java.util.*;
class Person implements Serializable {
// Устанавливаем serialVersionUID в статическое значение 123L.
private static final long serialVersionUID = 123L;
private String name;
private int age;
private double height;
private boolean married;
private int IQ; // это поле будет убрано при десериализации
// для демонстрации пользы статического значения SerialVersionUID
Person(String n, int a, double h, boolean m, int iq) {
name = n;
age = a;
height = h;
married = m;
IQ = iq;
}
String getName() { return name; }
int getAge() { return age; }
double getHeight() { return height; }
boolean getMarried() { return married; }
int getIQ() { return IQ; }
}
public class SerUid {
public static void main(String[] args) {
// Сериализуем
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“person.dat”))) {
Person p = new Person(“Sam”, 33, 178, true, 10);
// сериализуем класс (у него serialVersionUID = 123L)
oos.writeObject(p);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
Скомпилируем и запустим:
Объект сериализован в файл person.dat.
Теперь давайте десериализуем сериализованный объект, но класс Person уже будет изменен.
Также у новой версии класса поле SerialVersionUIDимеет то же значение, что и у прошлой версии класса, что позволяет десериализовать объект, пусть и, ясное дело, частично.
Пример программы:
import java.io.*;
import java.util.*;
class Person implements Serializable {
// все еще 123L как и раньше.
private static final long serialVersionUID = 123L;
private String name;
private int age;
private double height;
private boolean married;
// как видим поля ID больше здесь нет
Person(String n, int a, double h, boolean m) {
name = n;
age = a;
height = h;
married = m;
}
String getName() {
return name;
}
int getAge() {
return age;
}
double getHeight() {
return height;
}
boolean getMarried() {
return married;
}
}
public class SerUid {
public static void main(String[] args) {
// десериализация
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(“person.dat”))) {
// десериализуем объект
// класса с теперь уже удаленным полем IQ
// (serialVersionUID у класса
// десериализуемого объекта
// все еще 123L поэтому считать
// поля которые были в прошлой версии класса,
// то есть все кроме IQ можно)
Person p = (Person) ois.readObject();
System.out.printf(
“Name: %s \t Age: %d \t Height: %f \t Married: %b”,
p.getName(), p.getAge(), p.getHeight(),
p.getMarried());
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}