栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java——序列化和反序列化

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java——序列化和反序列化

文章目录
  • 什么是序列化和反序列化
  • 序列化和反序列化的使用
  • 如何保证反序列化后对象地址一致

什么是序列化和反序列化

序列化和反序列化一直都是一种很模糊的概念,关于理论有位大佬这么说到:

把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
参考博客:Java对象的序列化和反序列化

本篇博客对其不做过多的阐述,只是单纯的说明序列化和反序列化使用时需要注意的相关细节。

序列化和反序列化的使用

Java为了保证一个具有序列化和反序列化的能力,对其提供了一个接口java.io.Serializable。

只需要保证一个类实现他,就能完成对应的序列化和反序列化能力。

请看下列案例:

  • 1、定义一个类,实现Serializable

    class Demo implements Serializable {
        private String name;
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Demo{" +
                    "name='" + name + ''' +
                    ", age=" + age +
                    '}';
        }
    }
    
  • 2、编写测试代码,对象实例化后将其写入文件中

    package serializable;
    
    import java.io.*;
    
    public class SerializableTest {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            //System.out.println(System.getProperty("user.dir"));
            String names = System.getProperty("user.dir") + File.separator+"test"+File.separator+"serializable"+File.separator+"testSerializable";
    
            Demo demo = new Demo();
            demo.setName("xiangjiao");
            demo.setAge(24);
            System.out.println(demo.toString());
    
            // 将对象从内存中写到磁盘的指定文件中
            FileOutputStream fileOutputStream = new FileOutputStream(names);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(demo);
            objectOutputStream.close();
        }
    }
    

    代码执行后,其文件位置如下图所示:

  • 3、从指定文件中读取内容,并转化为对应的类

    package serializable;
    
    import java.io.*;
    
    public class SerializableTest {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            //System.out.println(System.getProperty("user.dir"));
            String names = System.getProperty("user.dir") + File.separator+"test"+File.separator+"serializable"+File.separator+"testSerializable";
    
            Demo demo = new Demo();
            demo.setName("xiangjiao");
            demo.setAge(24);
            System.out.println(demo.toString());
    
            // 将对象从内存中写到磁盘的指定文件中
    //        FileOutputStream fileOutputStream = new FileOutputStream(names);
    //        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
    //        objectOutputStream.writeObject(demo);
    //        objectOutputStream.close();
    
            // 从磁盘中读取文件
            FileInputStream fileInputStream = new FileInputStream(names);
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            Demo demo1 = (Demo) objectInputStream.readObject();
            objectInputStream.close();
    
            System.out.println(demo1.toString());
            System.out.println(demo == demo1);
        }
    }
    

    其运行结果如下所示:

【疑问:】这里的对象地址为啥不是一样的!

因为这个对象数据是JVM从数据流中解析出来的,并非是直接从堆中获取!

如何保证反序列化后对象地址一致

如果是为了测试必须保证对象地址一致,需要将序列化的子类以单例的形式进行测试。修改测试代码为单例模式,修改后的代码如下所示:

将对象信息序列化至磁盘文件中:

package serializable;

import java.io.*;

public class SerializableTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //System.out.println(System.getProperty("user.dir"));
        String names = System.getProperty("user.dir") + File.separator+"test"+File.separator+"serializable"+File.separator+"testSerializable";

        Demo instance = Demo.getInstance();
        System.out.println(instance);


        // 将对象从内存中写到磁盘的指定文件中
        FileOutputStream fileOutputStream = new FileOutputStream(names);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(instance);
        objectOutputStream.close();
    }
}

class Demo implements Serializable {
    private String name;
    private int age;

    private Demo (){}

    private Demo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 单例实例
    private static Demo demo = new Demo("xiangjiao",24);

    // 提供对外引用
    public static Demo getInstance(){
        return demo;
    }


    @Override
    public String toString() {
        return "Demo{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

当对象从内存序列化至磁盘文件后,再执行下列的反序列化操作:

package serializable;

import java.io.*;

public class SerializableTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //System.out.println(System.getProperty("user.dir"));
        String names = System.getProperty("user.dir") + File.separator+"test"+File.separator+"serializable"+File.separator+"testSerializable";

        Demo instance = Demo.getInstance();
        System.out.println(instance);


        // 将对象从内存中写到磁盘的指定文件中
//        FileOutputStream fileOutputStream = new FileOutputStream(names);
//        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//        objectOutputStream.writeObject(instance);
//        objectOutputStream.close();

        // 从磁盘中读取文件
        FileInputStream fileInputStream = new FileInputStream(names);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Demo demo1 = (Demo) objectInputStream.readObject();
        objectInputStream.close();

        System.out.println(demo1);
        System.out.println(instance == demo1);
    }
}

class Demo implements Serializable {
    private String name;
    private int age;

    private Demo (){}

    private Demo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 单例实例
    private static Demo demo = new Demo("xiangjiao",24);

    // 提供对外引用
    public static Demo getInstance(){
        return demo;
    }


    @Override
    public String toString() {
        return "Demo{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

此时控制台中运行的信息如下所示:

从运行结果中可以看出,当前两个对象的内存地址信息并不匹配。

当前是单例模型,如果内存地址不匹配,那也就说明采取序列化和反序列化操作,破坏了单例结构。

【思考:】如何才能解决这种问题呢,让其两个地址内存一致?

在java.io.Serializable的注释内容中,就已经对其进行了解释和说明。

那么我们就按照他说的来做,怎么使用呢?

在指定的类中,增加一个处理方法。

Object readResolve() throws ObjectStreamException{
    return demo;
}

再次执行代码:

package serializable;

import java.io.*;

public class SerializableTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //System.out.println(System.getProperty("user.dir"));
        String names = System.getProperty("user.dir") + File.separator+"test"+File.separator+"serializable"+File.separator+"testSerializable";

        Demo instance = Demo.getInstance();
        System.out.println(instance);


        // 将对象从内存中写到磁盘的指定文件中
//        FileOutputStream fileOutputStream = new FileOutputStream(names);
//        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//        objectOutputStream.writeObject(instance);
//        objectOutputStream.close();

        // 从磁盘中读取文件
        FileInputStream fileInputStream = new FileInputStream(names);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Demo demo1 = (Demo) objectInputStream.readObject();
        objectInputStream.close();

        System.out.println(demo1);
        System.out.println(instance == demo1);
    }
}

class Demo implements Serializable {
    private String name;
    private int age;

    private Demo (){}

    private Demo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 单例实例
    private static Demo demo = new Demo("xiangjiao",24);

    // 提供对外引用
    public static Demo getInstance(){
        return demo;
    }


    @Override
    public String toString() {
        return "Demo{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }

    Object readResolve() throws ObjectStreamException{
        return demo;
    }
}

运行后发现控制台出现以下报错信息:

出现这种问题的根源在于,文件中的序列化信息版本和现在已经更新过的版本不匹配。

在当前的序列化子类中,强制指定其版本号。如下所示:

private static final long serialVersionUID = -5461108964440966122L;

这里是这个数据,那是因为控制台中说明的。

重新生成对应文件,进行指定Java类的序列化和反序列化操作:

package serializable;

import java.io.*;
import java.util.concurrent.TimeUnit;

public class SerializableTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        //System.out.println(System.getProperty("user.dir"));
        String names = System.getProperty("user.dir") + File.separator+"test"+File.separator+"serializable"+File.separator+"testSerializable";

        Demo instance = Demo.getInstance();
        System.out.println(instance);


        // 将对象从内存中写到磁盘的指定文件中
        FileOutputStream fileOutputStream = new FileOutputStream(names);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(instance);
        objectOutputStream.close();

        TimeUnit.SECONDS.sleep(2);

        // 从磁盘中读取文件
        FileInputStream fileInputStream = new FileInputStream(names);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Demo demo1 = (Demo) objectInputStream.readObject();
        objectInputStream.close();

        System.out.println(demo1);
        System.out.println(instance == demo1);
    }
}

class Demo implements Serializable {
    private static final long serialVersionUID = -5461108964440966122L;
    private String name;
    private int age;

    private Demo (){}

    private Demo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 单例实例
    private static Demo demo = new Demo("xiangjiao",24);

    // 提供对外引用
    public static Demo getInstance(){
        return demo;
    }


//    @Override
//    public String toString() {
//        return "Demo{" +
//                "name='" + name + ''' +
//                ", age=" + age +
//                '}';
//    }

    Object readResolve() throws ObjectStreamException{
        return demo;
    }
}

运行后,此时的控制台中可以看到地址信息是匹配的,如下所示:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/396652.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号