java序列化

  1. java序列化的方式

(1)实现Serializable接口,在方法中定义readObject()与wirteObject()方法(注意这两个方法是要去自己定义的而且固定格式,并不是Serializable接口中定义的方法)

(2)实现Externalizable接口,并实现writeExternal()与readExternal()方法

  1. java序列化是在ObjectOutPutStream中实现的
public final void writeObject(Object obj) throws IOException {  //在序列化是调用这个方法
    if (enableOverride) {
        writeObjectOverride(obj);
        return;
    }
    try {
        writeObject0(obj, false);     //调用这个方法进行序列化
    } catch (IOException ex) {
        if (depth == 0) {
            writeFatalException(ex);
        }
        throw ex;
    }
}

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) {  //如果对象实现了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);
    }
}

private void writeOrdinaryObject(Object obj,
                                 ObjectStreamClass desc,
                                 boolean unshared)
    throws IOException
{
    if (extendedDebugInfo) {
        debugInfoStack.push(
            (depth == 1 ? "root " : "") + "object (class \"" +
            obj.getClass().getName() + "\", " + obj.toString() + ")");
    }
    try {
        desc.checkSerialize();

        bout.writeByte(TC_OBJECT);
        writeClassDesc(desc, false);
        handles.assign(unshared ? null : obj);
        if (desc.isExternalizable() && !desc.isProxy()) {  //如果实现了Externallizable接口则调用writeExternalData()方法
            writeExternalData((Externalizable) obj);
        } else {
            writeSerialData(obj, desc);         //否则调用writeSerialData()方法
        }
    } finally {
        if (extendedDebugInfo) {
            debugInfoStack.pop();
        }
    }
}

private void writeSerialData(Object obj, ObjectStreamClass desc)  //次方法中系统默认写入非transient部分
    throws IOException
{
    ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
    for (int i = 0; i < slots.length; i++) {
        ObjectStreamClass slotDesc = slots[i].desc;
        if (slotDesc.hasWriteObjectMethod()) {
            PutFieldImpl oldPut = curPut;
            curPut = null;
            SerialCallbackContext oldContext = curContext;

            if (extendedDebugInfo) {
                debugInfoStack.push(
                    "custom writeObject data (class \"" +
                    slotDesc.getName() + "\")");
            }
            try {
                curContext = new SerialCallbackContext(obj, slotDesc);
                bout.setBlockDataMode(true);
                slotDesc.invokeWriteObject(obj, this);
                bout.setBlockDataMode(false);
                bout.writeByte(TC_ENDBLOCKDATA);
            } finally {
                curContext.setUsed();
                curContext = oldContext;
                if (extendedDebugInfo) {
                    debugInfoStack.pop();
                }
            }

            curPut = oldPut;
        } else {
            defaultWriteFields(obj, slotDesc);   //主要执行方法
        }
    }
}

private void defaultWriteFields(Object obj, ObjectStreamClass desc)
    throws IOException
{
    Class> cl = desc.forClass();
    if (cl != null && obj != null && !cl.isInstance(obj)) {
        throw new ClassCastException();
    }

    desc.checkDefaultSerialize();

    int primDataSize = desc.getPrimDataSize();
    if (primDataSize > 0) {
        if (primVals == null || primVals.length < primDataSize) {
            primVals = new byte[primDataSize];
        }
        desc.getPrimFieldValues(obj, primVals);
        bout.write(primVals, 0, primDataSize, false);
    }

    int numObjFields = desc.getNumObjFields();
    if (numObjFields > 0) {
        ObjectStreamField[] fields = desc.getFields(false);
        Object[] objVals = new Object[numObjFields];
        int numPrimFields = fields.length - objVals.length;
        desc.getObjFieldValues(obj, objVals);
        for (int i = 0; i < objVals.length; i++) {
            if (extendedDebugInfo) {
                debugInfoStack.push(
                    "field (class \"" + desc.getName() + "\", name: \"" +
                    fields[numPrimFields + i].getName() + "\", type: \"" +
                    fields[numPrimFields + i].getType() + "\")");
            }
            try {
                writeObject0(objVals[i],
                             fields[numPrimFields + i].isUnshared());
            } finally {
                if (extendedDebugInfo) {
                    debugInfoStack.pop();
                }
            }
        }
    }
}



private ObjectStreamClass(final Class cl) {   //ObjectStreamClass类的构造方法
        this.cl = cl;
        name = cl.getName();
        isProxy = Proxy.isProxyClass(cl);
        isEnum = Enum.class.isAssignableFrom(cl);
        serializable = Serializable.class.isAssignableFrom(cl);
        externalizable = Externalizable.class.isAssignableFrom(cl);

        Class superCl = cl.getSuperclass();
        superDesc = (superCl != null) ? lookup(superCl, false) : null;
        localDesc = this;

        if (serializable) {
            AccessController.doPrivileged(new PrivilegedAction() {
                public Void run() {
                    if (isEnum) {
                        suid = Long.valueOf(0);
                        fields = NO_FIELDS;
                        return null;
                    }
                    if (cl.isArray()) {
                        fields = NO_FIELDS;
                        return null;
                    }

                    suid = getDeclaredSUID(cl);
                    try {
                        fields = getSerialFields(cl);
                        computeFieldOffsets();
                    } catch (InvalidClassException e) {
                        serializeEx = deserializeEx =
                            new ExceptionInfo(e.classname, e.getMessage());
                        fields = NO_FIELDS;
                    }

                    if (externalizable) {
                        cons = getExternalizableConstructor(cl);
                    } else {
                        cons = getSerializableConstructor(cl);
                        writeObjectMethod = getPrivateMethod(cl, "writeObject",          //在这里通过反射获取了writeObject方法
                            new Class[] { ObjectOutputStream.class },
                            Void.TYPE);
                        readObjectMethod = getPrivateMethod(cl, "readObject",        //在这里反射获取了readObject方法
                            new Class[] { ObjectInputStream.class },
                            Void.TYPE);
                        readObjectNoDataMethod = getPrivateMethod(
                            cl, "readObjectNoData", null, Void.TYPE);
                        hasWriteObjectData = (writeObjectMethod != null);
                    }
                    domains = getProtectionDomains(cons, cl);
                    writeReplaceMethod = getInheritableMethod(
                        cl, "writeReplace", null, Object.class);
                    readResolveMethod = getInheritableMethod(
                        cl, "readResolve", null, Object.class);
                    return null;
                }
            });
        } else {
            suid = Long.valueOf(0);
            fields = NO_FIELDS;
        }

        try {
            fieldRefl = getReflector(fields, this);
        } catch (InvalidClassException ex) {
            // field mismatches impossible when matching local fields vs. self
            throw new InternalError(ex);
        }

        if (deserializeEx == null) {
            if (isEnum) {
                deserializeEx = new ExceptionInfo(name, "enum type");
            } else if (cons == null) {
                deserializeEx = new ExceptionInfo(name, "no valid constructor");
            }
        }
        for (int i = 0; i < fields.length; i++) {
            if (fields[i].getField() == null) {
                defaultSerializeEx = new ExceptionInfo(
                    name, "unmatched serializable field(s) declared");
            }
        }
        initialized = true;
    }

undefined

undefined

  1. 为什么实现Serializable接口是需要自定义两个方法,并且格式固定?

根据上面的调用过程我们知道,实际上在序列化过程中对象中的这俩个方法是通过放射来调用的,由于调用方法的地方是固定的,所以只能在对象中使用固定的格式来完成。

Original: https://www.cnblogs.com/liwangcai/p/11885266.html
Author: 神奇海螺。
Title: java序列化

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/587113/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Spring Bean生命周期

    前言 Spring Bean生命周期是常见的面试题,也是日常开发中经常用到的技术点,在应用开发中,常常需要执行一些特殊的初始化工作,如建立数据库连接,打开网络连接,又比如在一些业务…

    Java 2023年5月30日
    062
  • windows系统cmd切换盘符路径命令失效

    问题描述:比如当我在C盘想切换到D盘的某个文件夹路径下时 只是输出了那个路径 但是并没有真的切换 这时候需要再多操作一步就会成功了 Original: https://www.cn…

    Java 2023年6月15日
    078
  • Typora

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年5月29日
    070
  • 2.分布式架构

    1.发展演变 1.单一应用架构 2.垂直应用架构 3.分布式服务架构 4.流动计算架构 posted @2022-07-27 19:44 努力的达子 阅读(44 ) 评论() 编辑…

    Java 2023年6月5日
    085
  • 常见的网页复制粘贴禁用问题

    1.网页无法选取文字 按下键盘的F12调出开发者工具,点击console控制台,输入以下代码后回车即可:解除网页无法选取文字 var eles = document.getElem…

    Java 2023年6月14日
    0134
  • (转)微信扫码登录网页实现原理

    扫码登录操作过程 浏览器输入:https://wx.qq.com/?lang=zh_CN 手机登录微信,利用”扫一扫”功能扫描网页上的二维码 手机扫描成功后…

    Java 2023年6月15日
    082
  • spring-boot-dependencies 和 spring-boot-starter-parent

    构建springboot项目有两种方式: 第一种是继承spring-boot-starter-parent pom里面指定parent项目: org.springframework…

    Java 2023年5月30日
    081
  • 集合篇-ConcurrentHashMap

    点赞再看,养成习惯,微信搜索「 小大白日志」关注这个搬砖人。 文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。 jdk1.7和jdk1.8中ConcurrentH…

    Java 2023年6月8日
    069
  • Spring Cloud认知学习(五):网关Zuul的使用

    💡这一篇介绍一个新的组件Zuul,Zuul是网关组件,对Api请求进行了统一的接收,基于网关,我们可以对所有的请求来进行处理,进行日志记录,请求授权等操作。 zuul可以作为微服务…

    Java 2023年5月30日
    094
  • Vulnhub-CTF5靶机实战

    前言 靶机下载地址:CTF5靶机下载地址 KALI地址:192.168.10.73靶机地址:192.168.10.116 一.信息收集 1.主机发现 使用命令如下 netdisco…

    Java 2023年6月13日
    084
  • Java调用C++动态链接库——Jni

    最近项目需要,将C++的算法工程编译成动态链接库,交给 Java后台当作函数库调用。就去了解了下Jni。使用起来还是比较方便的。 首先编写Java的调用类。例如: public c…

    Java 2023年6月16日
    097
  • IDEA:库源与类的字节码不匹配

    在我配置pom.xml文件后,进行代码编辑,发现引入的方法并不是想要的内容,然后我就进入下载源码后进入到源码中发现我想要的方法和导入的jar包内的源码方法并不相同 ,于是到jar的…

    Java 2023年6月13日
    088
  • 继承

    基本概念 扩充一个类已有的功能 优点 父类定义公共的内容,方便统一修改 整体减少代码量 添加新类方便 语法 class 子类 extends 父类{} 子类又叫派生类 父类又叫超类…

    Java 2023年6月6日
    080
  • 中国近代发展史顺序(二)

    建党初期: 1.中止一大:1921年7月 (上海、浙江嘉兴)宣告了中国共xx的成立,选举陈独秀为中央局书记。 2.中共二大:1922年7月 (上海)制定了党的最高纲领和最低纲领。 …

    Java 2023年6月5日
    074
  • JWT(JSON Web Token)的简单介绍及demo

    Original: https://www.cnblogs.com/qishanmozi/p/9761557.htmlAuthor: 祁山墨子Title: JWT(JSON Web…

    Java 2023年6月13日
    075
  • Hexo博客部署到腾讯云服务器全过程(Nginx,证书,HTTPS),你要的这里都有

    背景 说来也惭愧,博客已经搭建很久了,一直免费的部署在 Coding 和 Github Pages 上,前者迁移到腾讯云 Serverless,导致原有的配置始终有问题,没时间仔细…

    Java 2023年6月7日
    078
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球