IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 《Java基础知识》Java序列化与反序列化详解 -> 正文阅读

[Java知识库]《Java基础知识》Java序列化与反序列化详解

序列化的作用:为了不同jvm之间共享实例对象的一种解决方案.由java提供此机制。

序列化应用场景:

1. 分布式传递对象。

2. 网络传递对象。

3.?tomcat关闭以后会把session对象序列化到SESSIONS.ser文件中,等下次启动的时候就把这些session再加载到内存中。

完整案例:

import java.io.Serializable;

public class Box implements Serializable {

    public Box(){
        System.out.println("调用构造Box方法");
    }

    private String width;
    private String height;

    public String getWidth() {
        return width;
    }

    public void setWidth(String width) {
        this.width = width;
    }

    public String getHeight() {
        return height;
    }

    public void setHeight(String height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Box{" +
                "width=" + width +
                ", height=" + height +
                '}';
    }
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializableDemo {
    public static void main(String[] args){
        Box myBox = new Box();
        myBox.setWidth("50");
        myBox.setHeight("30");

        try{
            File file = new File("src\\demo\\knowledgepoints\\file\\foo.ser");

            //把对象信息写入文件中。
            ObjectOutputStream oout = new ObjectOutputStream (new FileOutputStream(file));
            oout.writeObject(myBox);
            oout.close();

            //把对象信息从文件中获取出来。
            ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
            Box newMyBox = (Box)oin.readObject(); // 没有强制转换到Person类型
            oin.close();
            System.out.println(newMyBox);
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

运行结果:

序列化相关注意事项:

??? a)序列化时,只对对象的状态进行保存,而不管对象的方法;

????b)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

??? c)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

? ? d)? 被序列化的对象需要 实现(Serializable)接口;

? ? e) 案例:构造方法没有执行,说明生成新对象,不是通过New出来的;

Java 对象被序列化需要实现(Serializable)接口,原因:

在 我们将对象序列化的类 ObjectOutputStream 的方法?writeObject0 中可以找到答案。

以下是JDK8的部分源码,红色字体部分就是原因。

private void writeObject0(Object obj, boolean unshared)
        throws IOException
    {
        boolean oldMode = bout.setBlockDataMode(false);
        depth++;
        try {
            // handle previously written and non-replaceable objects
            int h;
            if ((obj = subs.lookup(obj)) == null) {
                writeNull();
                return;
            } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                writeHandle(h);
                return;
            } else if (obj instanceof Class) {
                writeClass((Class) obj, unshared);
                return;
            } else if (obj instanceof ObjectStreamClass) {
                writeClassDesc((ObjectStreamClass) obj, unshared);
                return;
            }

            // check for replacement object
            Object orig = obj;
            Class<?> cl = obj.getClass();
            ObjectStreamClass desc;
            for (;;) {
                // REMIND: skip this check for strings/arrays?
                Class<?> repCl;
                desc = ObjectStreamClass.lookup(cl, true);
                if (!desc.hasWriteReplaceMethod() ||
                    (obj = desc.invokeWriteReplace(obj)) == null ||
                    (repCl = obj.getClass()) == cl)
                {
                    break;
                }
                cl = repCl;
            }
            if (enableReplace) {
                Object rep = replaceObject(obj);
                if (rep != obj && rep != null) {
                    cl = rep.getClass();
                    desc = ObjectStreamClass.lookup(cl, true);
                }
                obj = rep;
            }

            // if object replaced, run through original checks a second time
            if (obj != orig) {
                subs.assign(orig, obj);
                if (obj == null) {
                    writeNull();
                    return;
                } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                    writeHandle(h);
                    return;
                } else if (obj instanceof Class) {
                    writeClass((Class) obj, unshared);
                    return;
                } else if (obj instanceof ObjectStreamClass) {
                    writeClassDesc((ObjectStreamClass) obj, unshared);
                    return;
                }
            }

            // remaining cases
            if (obj instanceof String) {
                writeString((String) obj, unshared);
            } else if (cl.isArray()) {
                writeArray(obj, desc, unshared);
            } else if (obj instanceof Enum) {
                writeEnum((Enum<?>) obj, desc, unshared);
            } else if (obj instanceof Serializable) {
                writeOrdinaryObject(obj, desc, unshared);
            } else {
                if (extendedDebugInfo) {
                    throw new NotSerializableException(
                        cl.getName() + "\n" + debugInfoStack.toString());
                } else {
                    throw new NotSerializableException(cl.getName());
                }
            }
        } finally {
            depth--;
            bout.setBlockDataMode(oldMode);
        }
    }

如何将序列化控制在自己手中?

1. 通过关键字【transient】实现,字段值不被序列化。

改一下Box类:

import java.io.Serializable;

public class Box implements Serializable {

    public Box(){
        System.out.println("调用构造Box方法");
    }

    // 关键字:transient 控制width不被序列化,保护数据。
    private transient String width;
    private String height;

    public String getWidth() {
        return width;
    }

    public void setWidth(String width) {
        this.width = width;
    }

    public String getHeight() {
        return height;
    }

    public void setHeight(String height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Box{" +
                "width=" + width +
                ", height=" + height +
                '}';
    }
}

运行结果:

这个box的width值被擦除了。

2. writeObject()方法与readObject()方法。

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Box implements Serializable {

    public Box(){
        System.out.println("调用构造Box方法");
    }

    // 关键字:transient 控制width不被序列化,保护数据。
    private transient String width;
    private String height;

    public String getWidth() {
        return width;
    }

    public void setWidth(String width) {
        this.width = width;
    }

    public String getHeight() {
        return height;
    }

    public void setHeight(String height) {
        this.height = height;
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeChars(width);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        width = in.readLine();
    }

    @Override
    public String toString() {
        return "Box{" +
                "width=" + width +
                ", height=" + height +
                '}';
    }
}

运行结果:

加入writeObject()方法与readObject()方法后,width值又回来了,这两个方法都是私有的,已经可以基本猜测是通过反射调用方法,赋值的。

3.Externalizable 接口,自定义实现写入和读取序列化对象

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class BoxTmp implements Externalizable {
    public BoxTmp(){
        System.out.println("调用构造Box方法");
    }

    private String width;
    private String height;

    public String getWidth() {
        return width;
    }

    public void setWidth(String width) {
        this.width = width;
    }

    public String getHeight() {
        return height;
    }

    public void setHeight(String height) {
        this.height = height;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeChars(width+","+width);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        String str = in.readLine();
        this.width = str.split(",")[0];
        this.height = str.split(",")[1];
    }

    @Override
    public String toString() {
        return "BoxTmp{" +
                "width='" + width + '\'' +
                ", height='" + height + '\'' +
                '}';
    }
}
public class ExternalizableDemo {
    public static void main(String[] args){
        BoxTmp boxTmp = new BoxTmp();
        boxTmp.setWidth("50");
        boxTmp.setHeight("30");

        try{
            File file = new File("src\\demo\\knowledgepoints\\file\\foo.txt");

            //把对象信息写入文件中。
            ObjectOutputStream oout = new ObjectOutputStream (new FileOutputStream(file));
            oout.writeObject(boxTmp);
            oout.close();

            //把对象信息从文件中获取出来。
            ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
            BoxTmp newBoxTmp = (BoxTmp)oin.readObject(); // 没有强制转换到Person类型
            oin.close();
            System.out.println(newBoxTmp);
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

运行结果:

Externalizable接口中的writeExternal和readExternal 方法可以用来自定义实现值的传递,覆盖等其他操作。

同时构造方法被执行了,说明这个类是被new出来后,由你支配。

4. readResolve()方法

import java.io.ObjectStreamException;
import java.io.Serializable;

public class Box implements Serializable {

    public static Box box = new Box();

    public Box(){}

    public Box(String height,String width){
        this.height = height;
        this.width = width;
    }

    public static Box getInstance() {
        if(box == null){
            box = new Box("20","10");
        }
        return box;
    }

    private String width;
    private String height;

    public String getWidth() {
        return width;
    }

    public void setWidth(String width) {
        this.width = width;
    }

    public String getHeight() {
        return height;
    }

    public void setHeight(String height) {
        this.height = height;
    }

    private Object readResolve() throws ObjectStreamException {
        return Box.box;
    }
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializableDemo {
    public static void main(String[] args){
        Box myBox = Box.getInstance();
        try{
            File file = new File("src\\demo\\knowledgepoints\\file\\foo.ser");

            //把对象信息写入文件中。
            ObjectOutputStream oout = new ObjectOutputStream (new FileOutputStream(file));
            oout.writeObject(myBox);
            oout.close();

            //把对象信息从文件中获取出来。
            ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
            Box newMyBox = (Box)oin.readObject(); // 没有强制转换到Person类型
            oin.close();
            System.out.println("newMyBox == myBox : "+(newMyBox == myBox));
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

运行结果:

Box类中实现readResolve() 方法可以实现单例对象还是同一个。


尚学堂给同学们带来全新的Java300集课程啦!java零基础小白自学Java必备优质教程_手把手图解学习Java,让学习成为一种享受_哔哩哔哩_bilibili

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-06-21 21:21:07  更:2022-06-21 21:22:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:08:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码