类对象的持久化与序列化

1、所谓类对象的持久化是指:把内存中的对象存储在某种介质上(除内存外,包括硬盘或者网络存储传输等),当然持久化的完整操作并不只是为了把对象数据以字节码或字节流的形式存储在介质上,它还要包括对持久化的对象读取与验证。

2、所谓类对象的序列化是指:把一个类对象转化为字节流或字节码(把一个字节流对象转化为一个类对象过程称为反序列化),同时保存其状态等一些特性。对象序列化需要继承Serializable接口,它的作用只是标识该类的对象可以被序列化,并同时会自动生成一个属性serialVersionUID值,用来版本控制或验证该类的持久化对象在不同版本中是否兼容(?)。
java的序列化机制是通过在运行时来判断serialVersionUID值的一致性来验证版本。在进行反序列化时JVM会把获得序列化字节流中的serialVersionUID值与本地对应的类中的serialVersionUID值进行比较,如果一致,则进行反序列化操作,否则,则报版本不一致的无效类。

3、但是对象的序列化与持久化之间是什么关系那?
对象的持久化前提是对象的序列化。
为什么持久化之前需要序列化那?
序列化是综合很多种情况下的解决方案:举个例子
假设有A和B两个类,A中有一个属性字段是B类的引用那么在对A和B进行持久化的时候,A中包含B的引用,那么需要把B的数据复制一份给A,但当对A和B反序列的时候,系统内存中会出现两份对象B或B占用两份内存空间,这样对于数据修改保存都会出现问题。
序列化机制解决了以下问题:
1、一个对象序列化唯一对应一个序列化值(serialVersionUID)。
2、当要持久化一个对象时,先检查该对象是否已经持久化。
3、如果已经保存,则需要标记与已有对象序列号相同标记。
4、对于网络传输或者读取其他方式获得的字节码流进行反序列化验证。
4、序列化测试代码
序列化实体类:

package com.serializable.entity;

import java.io.Serializable;

public class Person implements Serializable{
    private String name;
    private int age;

    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    } 
}

持久化代码:

package com.serializable.serializable;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

import com.serializable.entity.Person;

public class SerializableTest {
    public static void main(String[] args) throws IOException {
        Person pn= new Person("张三",26);
        FileOutputStream fos=new FileOutputStream("person.txt");
        ObjectOutputStream oos=new ObjectOutputStream(fos);
        oos.writeObject(pn);
        oos.close();
        fos.close();
        System.out.println(pn.toString());  
    }
}

反序列化代码:

package com.serializable.deserializable;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

import com.serializable.entity.Person;

public class DeSerializableTest  {
public static void main(String[] args) throws IOException, ClassNotFoundException {
    FileInputStream fis=new FileInputStream("person.txt");
    ObjectInputStream ois=new ObjectInputStream(fis);
    Person pn=(Person)ois.readObject();
    System.out.println(pn.toString());
    ois.close();
    fis.close();
}
}

在序列化与反序列化过程中,只要序列号一致,就可以进行正常操作。
注意:如果没有在代码类中显式定义serialVersionUID的值,那么系统会根据类的属性等一系列特性生成一个serialVersionUID,只要修改参与生成serialVersionUID的部分,就会生成不同的serialVersionUID,从而会反序列化报错。
但是如果在代码中显式定义了serialVersionUID值,那么在序列化前后增加()属性字段值,serialVersionUID是没有改变的,是可以正常序列化的。
以下情况是显式定义了serialVersionUID值,并且没有改变。
在网络传输中,如果A端持久化后,另一端B新增字段值,但没有去改变serialVersionUID值,那么在反序列化时,对于B新增而A没有的字段值,如果是String类型,则默认为null,如果是int 则默认为0……
对于A端新增字段,B端不变则B端反序列化的时候忽略A端新增的字段值。
(serialVersionUID值一致,反序列时,如果该端本地类比另一端少的字段则忽略,如果比另一端多的字段值则是默认的值 比如 int类型为0)

猜你喜欢

转载自blog.csdn.net/qq_26564827/article/details/78580863