-
序列化:(方便在磁盘上存储或者在网络上传输)把对象转换为字节序列的过程称为对象的序列化。
-
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
-
利用ObjectOutputStream和ObjectInputStream序列化和反序列化时一定要实现Serializable接口,否则会报
NotSerializableException
异常 -
利用fastjson序列化字符串时不实现Serializable不会报异常(fastjson使用的是反射,通过get方法获取属性,如果没有get方法就直接访问属性,如果属性的访问修饰符为private就拿不到,在fastjson将对象转为字符串的过程中不会修改属性的访问修饰符,transient修饰的字段也不会参数转字符串)
@Data
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
public static int id;
private String name;
private int age;
// 参与序列化的类也必须能序列化,否则会报 NotSerializableException
private Pet pet;
private transient Car car;
private int height;
public static void main(String[] args) {
serializePerson();
deserializePerson();
}
private static void serializePerson() {
Person person = new Person();
person.setName("张三三");
person.setAge(18);
person.setPet(new Pet("大黄"));
person.setCar(new Car("奥迪"));
Person.id = 1;
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.txt"))) {
out.writeObject(person);
System.out.println("序列化完成");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("JSON.toJSONString(person):"+JSON.toJSONString(person));
}
private static void deserializePerson() {
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("person.txt"))) {
Person readObject = (Person) in.readObject();
System.out.println("readObject = " + readObject);
System.out.println(Person.id);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Data
public class Car {
private String name;
public Car(String name) {
this.name = name;
}
}
@Data
public class Pet implements Serializable {
private String name;
public Pet(String name) {
this.name = name;
}
}
序列化完成
JSON.toJSONString(person):{"age":18,"height":0,"name":"张三三","pet":{"name":"大黄"}}
readObject = Person(name=张三三, age=18, height=0, pet=Pet(name=大黄), car=null)
1
说明:
-
静态成员变量不能序列化(序列化)
-
transient修饰的成员变量不参与序列化
-
参与序列化的引用类型也必须实现Serializable接口,否则会报NotSerializableException异常
@Data public class Person implements Serializable { private static final long serialVersionUID = 1L; private String name; private Pet pet; public static void main(String[] args) throws CloneNotSupportedException, FileNotFoundException { Person person = new Person(); person.setName("张三"); Pet pet = new Pet(); pet.setName("大黄"); person.setPet(pet); try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("person.txt"))) { outputStream.writeObject(person); } catch (IOException e) { e.printStackTrace(); } } }
@Data public class Pet { private String name; }
java.io.NotSerializableException: com.example.hello.mianshi.Pet at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) at com.example.hello.mianshi.Person.main(Person.java:23)
-
最好显示提供serialVersionUID
实现 Serializable 接口的类不显式地声明 serialVersionUID 字段时,Java 会自动生成一个 serialVersionUID,这种方式的缺点是它会基于类的结构自动生成一个 serialVersionUID,可能会因为类的修改而改变。当serialVersionUID不一致时就会报InvalidClassException异常
序列化时有name和age
@Data public class Person implements Serializable { private String name; private int age; public static void main(String[] args) throws CloneNotSupportedException, FileNotFoundException { serialize(); } private static void serialize() { Person person = new Person(); person.setName("张三"); person.setAge(18); try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("person.txt"))) { outputStream.writeObject(person); } catch (IOException e) { e.printStackTrace(); } } }
反序列化时少了age,多了gender
@Data public class Person implements Serializable { private String name; private String gender; public static void main(String[] args) throws CloneNotSupportedException, FileNotFoundException { deserialize(); } private static void deserialize() { try (ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("person.txt"))) { Object o = inputStream.readObject(); System.out.println("o = " + o); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }
报错
java.io.InvalidClassException: com.example.hello.mianshi.Person; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 1518472723010370216 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1885) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
加上serialVersionUID
@Data public class Person implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age; public static void main(String[] args) throws CloneNotSupportedException, FileNotFoundException { serialize(); } private static void serialize() { Person person = new Person(); person.setName("张三"); person.setAge(18); try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("person.txt"))) { outputStream.writeObject(person); } catch (IOException e) { e.printStackTrace(); } } }
@Data public class Person implements Serializable { private static final long serialVersionUID = 1L; private String name; private String gender; public static void main(String[] args) throws CloneNotSupportedException, FileNotFoundException { deserialize(); } private static void deserialize() { try (ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("person.txt"))) { Object o = inputStream.readObject(); System.out.println("o = " + o); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }
o = Person(name=张三, gender=null)
-
可序列化类的所有子类型本身都是可序列化的。因为实现接口也是间接的等同于继承。
-
利用fastjson等工具时,不实现Serializable不会报错,