java如何反序列化?

 2024-03-19 05:09:06  阅读 0

当遇到这个Java序列化接口时,我们可能会遇到以下问题

当我第一次看到这个关键词时,我有以下疑问。

在处理这个问题之前,首先要了解一个问题,这是比较重要的。

这个接口,以及相关的东西,都是Java io中的。

1. 序列化和反序列化的概念

以上是专业的解释,现在我们来通俗地解释一下。 代码运行的时候,我们可以看到很多对象(都已经调试过了),这些对象可以是一个,也可以是某个类型的对象的集合,很多对象数据,而在这些数据中,有一些信息,我们想要永久保存,那么这就叫序列化。

它是将内存中的这些对象转换为一系列字节的过程。 最常见的就是把它变成一个文件。 我可以保存文件而无需序列化。 有什么影响? 我也是这么问的。

2、什么情况下需要序列化?

当你想将内存中的对象状态保存到文件或数据库时;

当你想使用套接字通过网络发送对象时;

当你想通过RMI传输对象时;

(老实说,在上面的内容中,我可能只使用了存储数据库的内容。)

3. java中如何实现序列化

只需实现接口即可

上述理论都比较简单。 让我们看一下下面的实际代码,看看这个序列化可以做什么以及它会导致什么错误。

让我们从目标代码开始,.java

package com.lxk.model;
import java.io.Serializable;
/**
 * @author lxk on 2017/11/1
 */
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 addTip;

    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;
    }
    //public String getAddTip() {
    //    return addTip;
    //}
    //
    //public void setAddTip(String addTip) {
    //    this.addTip = addTip;
    //}

    @Override
    public String toString() {
        return "FlyPig{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", car='" + car + '\'' +
                ", AGE='" + AGE + '\'' +
                //", addTip='" + addTip + '\'' +
                '}';
    }
}

注意,后面的各种情况都会用到注释掉的代码。

这是主要方法

package com.lxk.test;
import com.lxk.model.FlyPig;
import java.io.*;
/**
 * 序列化测试
 *
 * @author lxk on 2017/11/1
 */
public class SerializableTest {
    public static void main(String[] args) throws Exception {
        serializeFlyPig();
        FlyPig flyPig = deserializeFlyPig();
        System.out.println(flyPig.toString());
    }
    /**
     * 序列化
     */
    private static void serializeFlyPig() throws IOException {
        FlyPig flyPig = new FlyPig();
        flyPig.setColor("black");
        flyPig.setName("naruto");
        flyPig.setCar("0000");
        // ObjectOutputStream 对象输出流,将 flyPig 对象存储到E盘的 flyPig.txt 文件中,完成对 flyPig 对象的序列化操作
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:/flyPig.txt")));
        oos.writeObject(flyPig);
        System.out.println("FlyPig 对象序列化成功!");
        oos.close();
    }
    /**
     * 反序列化
     */
    private static FlyPig deserializeFlyPig() throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:/flyPig.txt")));
        FlyPig person = (FlyPig) ois.readObject();
        System.out.println("FlyPig 对象反序列化成功!");
        return person;
    }
}

简单解释一下上面两个操作文件流的类

表示对象输出流:

它的 (obj) 方法可以序列化参数指定的 obj 对象,并将结果字节序列写入目标输出流。

表示一个对象输入流:

它的 () 方法从源输入流中读取字节序列,将它们反序列化为对象,然后返回它。

具体如何查看运行状态。

第一个:只要拿出这些代码,不动地运行它们,看看效果。

实际运行结果会生成为d:/.txt文件。

java 反序列化_序列化反序列化_序列化反序列化多线程

从运行结果来看:

第二种方法:为了验证这个静态属性是否可以序列化和反序列化,可以执行以下操作。

public static void main(String[] args) throws Exception {
        serializeFlyPig();
        //FlyPig flyPig = deserializeFlyPig();
        //System.out.println(flyPig.toString());
    }

这完成之后,就意味着你首先将对象序列化到文件中。 该对象具有静态变量。

现在将类中AGE的值修改为26。

然后,看看下图的运行代码和执行结果。

可以看到,刚刚序列化的269并没有被读出。 就是刚刚修改的26。 如果可以的话,这个26应该被覆盖掉,应该是269。

因此,断定这个静态属性没有被序列化。

第三种:演示这个的功能和用法

最暴力的修改就是直接去掉模型类实现的接口。 然后执行后续的序列化和反序列化方法。 直接报错。

抛出异常:

序列化反序列化_序列化反序列化多线程_java 反序列化

这个太暴力了,不推荐。

然后,与上面的操作类似。 首先,单独执行序列化方法。 生成文件。

然后,打开属性,然后再次执行反序列化方法即可看到现象。

序列化反序列化_序列化反序列化多线程_java 反序列化

抛出异常:n 详细信息如下。

InvalidClassException: com.lxk.model.FlyPig; 
local class incompatible: 
stream classdesc serialVersionUID = -3983502914954951240, 
local class serialVersionUID = 7565838717623951575

解释:

因为我没有在模型中显式地给this赋值,但是Java会自动给我赋值。 该值的计算与模型的属性相关。

我保存的时候,也就是序列化的时候,当时这个属性是不存在的。 因此,自动生成的值与我反序列化时Java自动生成的值不同,并且抛出了异常。 拉。

(也可以反过来,用ID序列化,然后不带ID反序列化。同样的问题。)

我们再来一遍,即先序列化。 此时打开评论最后long = 1L; 行代码。 先注释掉该属性,序列化后,打开该属性,再次反序列化。 走着瞧吧。

序列化反序列化多线程_java 反序列化_序列化反序列化

此时代码执行正常,一切正常。 好的。 序列化时,该属性丢失。 序列化时,对应的模型有一个附加属性。 但是反序列化执行正常,没有出现异常。

这种现象对我们意味着什么:

老铁,这个意义重大。 首先,如果你不知道这个序列化是做什么用的,万一他真的像开头说的那样保存数据库呢(这个保存db是否涉及到Java的序列化大概要看什么数据库?),传输,rmi传输。 虽然我不知道这是干什么用的。 您只需为模型 bean 实现此接口即可。 如果不写这个,那么以后扩展的时候,可能会出现不识别旧数据的bug,就会爆炸。 回忆一下上面的错误情况。 想想都觉得可怕。 谁来承担责任?

因此,有一种理论是,在实现这个接口的时候,必须要给它赋值。 这就是问题。

这也解释了为什么我们刚开始编码的时候,实现这个接口后,编辑器给出了黄色警告,需要添加这个ID的值。 这是一长串数字,你甚至不知道它们来自哪里。

下面说明如何设置这个值才可以。

首先,你不需要自己赋值,Java会帮你赋值。 但是这样会导致上面的bug,非常不安全,所以必须手动进行。

那么,我应该如何赋值呢? 它可能会自动为您分配一长串号码。 这是没有必要的。

您可以简单地指定 1L 的值,仅此而已。 。 这可以确保在代码一致的情况下反序列化成功。

不同的值会影响反序列化,即数据读取。 如果写1L,请注意L更大。 计算机不区分大小写,但作为查看者,我们需要区分1和L,所以没事的时候不要乱乱这个值。 否则,当版本升级时,旧数据将不兼容。 还是不知道问题出在哪里。 **。

以下是取自jdk api文档的接口描述。

一个类实现了 java.io. 接口以启用其序列化功能。 未实现此接口的类将无法序列化或反序列化其任何状态。 可序列化类的所有子类型本身都是可序列化的。 因为实现接口也间接相当于继承。 序列化接口没有方法或字段,仅用于标识可序列化语义。

描述关于

序列化反序列化_序列化反序列化多线程_java 反序列化

(注意对比,这张截图中的两段对应下面的两段中文,如果你仔细看这两段,就可以解释43楼的问题了。静态属性不会被序列化,但是有一个特殊的静态属性会被序列化,没办法,这个静态属性是原生的,自带的。)

序列化运行时使用称为“兼容类”的版本号与每个可序列化类关联。 如果接收方加载的对象类的版本号与相应发送方的类的版本号不同,则反序列化将导致 n。 可序列化类可以通过声明名为“”的字段(必须是 ()、final(long) 字段)来显式声明自己:

如果未显式声明可序列化类,则序列化运行时会根据该类的各个方面计算该类的默认值,如“Java(TM) 对象序列化规范”中所述。 但是,强烈建议所有可序列化类显式声明值,因为计算默认值对类的细节高度敏感,并且可能会根据编译器实现而有很大差异,这可能会在反序列化期间导致问题。 导致意外的 n.

因此,为了确保该值在不同的 Java 编译器实现中保持一致,序列化类必须声明一个显式值。 还强烈建议对显式声明使用修饰符(如果可能),原因是此类声明只能用于直接声明类——字段不能用作继承成员。 数组类无法声明显式的值,因此它们始终具有默认的计算值,但数组类不要求匹配这些值。

来源:/20131.html

标签: 序列 声明 静态

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码