序列化和反序列化的理解

序列化的含义和意义

含义:

把对象转换为字节序列的过程称为对象的序列化
把字节序列恢复为对象的过程称为对象的反序列化。

意义:

1.把对象的字节序列永久的保存到硬盘上,通常存在一个文件中

2.在网络上传送对象的字节序列

》》》》》

》对象序列化的目标是将对象保存到磁盘中,或允许在网络中直接传输对象,对象序列化机制允许把内存中的java对象转换成与平台无关的二进制流,从而允许把这种二进制流持久持久的保存在磁盘上,通过网络将这种二进制流传输到另一个网络节点。其他程序一旦获得了这种二进制流(无论是从磁盘中获取的,还是通过网络获取的)都可以将这种二进制流恢复成原来的java对象。

》 序列化机制允许将实现序列化的java对象转换成字节序列,这些字节序列可以保存在磁盘中,或通过网络传输,以备以后重新恢复成原来的对象,序列化机制使得对象可以脱离程序的运行而独立存在。

》 对象的序列化是指将一个java对象写入IO流中,于此对应的是对象的反序列化是指从IO流中恢复该java对象。

》 如果需要让某个对象支持序列化机制,则必须让他的类是可序列化的。为了让某个类是可序列化的,该类必须实现如下二个接口之一:
》 Serializable或Externalizable
》 java中的含多类已经实现了Serializable,该接口是一个标记接口,实现该接口无需事先任何方法,它只是表明该类的实例是可序列化的。

》 所有可能在网络上传输的对象的类都应该是可序列化的,否则,程序将会出现异常,比如,RMI(远程调用方法)过程中的参数和返回值;所有需要保存在磁盘的对象都必须是可序列化的。比如Web应用中需要保存到HttpSession或ServleContext属性的java对象。

》因为序列化是RMI‘过程中的参数和返回值都必须实现的机制,而RMI又是javaEE技术的基础,所有的分布式应用常常都需要跨平台、跨网络,所以要求所有传递的参数,返回值必须实现序列化,因此,序列化机制是javaEE平台的基础,通常建议:程序创建的每个javaBean类都实现Serializable。

序列化及反序列化相关知识

1、在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化。

2、通过ObjectOutputStream和ObjectInputStream对对象进行序列化及反序列化

3、虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID)

4、序列化并不保存静态变量,因为静态变量属于类的状态,不是对象的状态。

5、要想将父类对象也序列化,就需要让父类也实现Serializable 接口。

6、Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

7、服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取,这样可以一定程度保证序列化对象的数据安全。

序列化 ID 问题

1.虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)

2.序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。那么随机生成的序列化 ID 有什么作用呢,有些时候,通过改变序列化 ID 可以用来限制某些用户的使用。

ID工作机制:

序列化的时候系统会把当前类的serialVersionUID 写入序列化的文件中(也可能是其他中介),当反序列化的时候系统会去检测文件中的serialVersionUID ,看它是否和当前类的serialVersionUID 一致,如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化,否则就说明当前类和序列化的类相比发生了某些变换,比如成员变量的数量,类型可能发生了改变,这个时候就会抛异常,反序列化失败。

serialVersionUID作用:

作用:

序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。

那么serialVersionUID 是如何生成,生成规则是怎么样的呢?

默认情况下,也就是不声明serialVersionUID 属性情况下,系统会按当前类的成员变量计算hash值并赋值给serialVersionUID 。

所以,结论就出来了。声明serialVersionUID ,可以很大程度上避免反序列化过程的失败。比如当版本升级后,我们可能删除了某个成员变量,也可能增加了一些新的成员变量,这个时候我们的反序列化依然能够成功,程序依然能够最大程度地恢复数据,相反,如果不指定serialVersionUID ,程序就会挂掉。

如果类结构发生了非常规性改变,比如修改了类名,类型等,这个时候尽管serialVersionUID 验证通过了,但是反序列化过程还是会失败,因为类结构有了毁灭性的改变。

序列化的使用时机:

一:对象序列化可以实现分布式对象。
主要应用例如:RMI(即远程调用Remote Method Invocation)要利用对象序列化运行远程主机上的服务,就像在本地机上运行对象时一样。
二:java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。可以将整个对象层次写入字节流中,可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象的”深复制”,即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。
三:序列化可以将内存中的类写入文件或数据库中。
比如将某个类序列化后存为文件,下次读取时只需将文件中的数据反序列化就可以将原先的类还原到内存中。也可以将类序列化为流数据进行传输。总的来说就是将一个已经实例化的类转成文件存储,下次需要实例化的时候只要反序列化即可将类实例化到内存中并保留序列化时类中的所有变量和状态。
四: 对象、文件、数据,有许多不同的格式,很难统一传输和保存序列化以后就都是字节流了,无论原来是什么东西,都能变成一样的东西,就可以进行通用的格式传输或保存,传输结束以后,要再次使用,就进行反序列化还原,这样对象还是对象,文件还是文件
因为JAVA中要将对象序列化 为 流 的 形式进行传输

import java.io.Serializable;

public class FlyPig implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private static String age = "269";
    private String name;
    private String color;
    transient private String car;
    private String weight;

    public void show() {
        System.out.println("nisfisf");
    }

    public FlyPig(String name, String color, String car, String weight) {
        super();
        this.name = name;
        this.color = color;
        this.car = car;
        this.weight = weight;
    }

    public FlyPig() {
        super();
        // TODO Auto-generated constructor stub
    }

    public static String getAge() {
        return age;
    }

    public static void setAge(String age) {
        FlyPig.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getCar() {
        return car;
    }

    public void setCar(String car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "FlyPig [name=" + name + ", color=" + color + ", car=" + car + "]";
    }

    public String getWeight() {
        return weight;
    }

    public void setWeight(String weight) {
        this.weight = weight;
    }

}
**import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.junit.Before;
import org.junit.Test;

public class Test1 {
    private FlyPig flypig;

    @Before
    public void te() {
        flypig = new FlyPig();
    }

    @Test
    public void test() throws FileNotFoundException, IOException {

        flypig.setColor("black");
        flypig.setName("na");
        flypig.setCar("333");
        flypig.setWeight("sdfs");

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("f:/flypif.txt")));
        oos.writeObject(flypig);
        System.err.println("序列化成功");
        oos.close();

    }

    @Test
    public void test1() throws FileNotFoundException, IOException, ClassNotFoundException {

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("f:/flyPig.txt")));
        FlyPig person = (FlyPig) ois.readObject();
        System.out.println("FlyPig 对象反序列化成功!");
        System.out.println(person);
        person.show();

        ois.close();

    }

}**

猜你喜欢

转载自blog.csdn.net/qq_32269393/article/details/79561382