Java反序列化与对象的创建

【实战解析】SAP EWM与PP深度集成:从后台配置到前台物料流转的全链路设计 本文深入解析SAP EWM与PP深度集成的全链路设计,涵盖后台配置与前台物料流转的实战应用。通过两种集成模式(DPI与API)的选择策略、十二个关键后台配置步骤详解,以及PMR生成、PSA补货等前台演示,帮助企业实现生产计划与物料供应的高效协同,显著提升生产效率和库存周转率。 阅读详情

Java与单例模式一文中提到了,Java可以通过反序列化来破坏单例,其底层就是利用反射,通过一个代表无参构造方法的Constructor对象,使用其newInstance()方法来创建对象。

但是,在后续的测试代码中发现,其实目标类的无参构造方法并没有执行!所以,对于这个对象的创建过程并不是我一开始想的那样。请看下面的例子:

// 目标类
public class Elvis implements Serializable {
    public static final Elvis INSTANCE = new Elvis();

    public Elvis() {
        System.out.println("no parameters constructor invoked!");
    }
}

// 测试
@Test
public void testSerialization() throws Exception {
    Elvis elvis1 = Elvis.INSTANCE;
    FileOutputStream fos = new FileOutputStream("a.txt");
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    oos.writeObject(elvis1);
    oos.flush();
    oos.close();

    Elvis elvis2 = null;
    FileInputStream fis = new FileInputStream("a.txt");
    ObjectInputStream ois = new ObjectInputStream(fis);
    elvis2 = (Elvis) ois.readObject();

    System.out.println("elvis1与elvis2相等吗? ===> " + (elvis1 == elvis2));
}

结果:

no parameters constructor invoked!
elvis1与elvis2相等吗? ===> false

public static final Elvis INSTANCE = new Elvis();是对象第一次实例化,所以第一行的打印no parameters constructor invoked是这个时候执行的。Elvis的构造方法只执行了一次,所以反序列化的时候,Java没有去调用目标类的构造方法来创建对象。

回顾反序列化过程的Java代码,在ObjectInputStream类中的Object readOrdinaryObject(boolean)方法中。如下:

private Object readOrdinaryObject(boolean unshared)
        throws IOException {
    //此处省略部分代码

    ObjectStreamClass desc = readClassDesc(false);
    desc.checkDeserialize();

    Class<?> cl = desc.forClass();
    if (cl == String.class || cl == Class.class || cl == ObjectStreamClass.class) {
          throw new InvalidClassException("invalid class descriptor");
    }

    Object obj;
    try {
        obj = desc.isInstantiable() ? desc.newInstance() : null;
    } catch (Exception ex) {
        throw (IOException) new InvalidClassException(
            desc.forClass().getName(),
            "unable to create instance").initCause(ex);
    }

    //此处省略部分代码

    if (obj != null &&
        handles.lookupException(passHandle) == null &&
        desc.hasReadResolveMethod())
    {
        Object rep = desc.invokeReadResolve(obj);
        if (unshared && rep.getClass().isArray()) {
            rep = cloneArray(rep);
        }
        if (rep != obj) {
            handles.setObject(passHandle, obj = rep);
        }
    }

    return obj;
}

重点代码块:

obj = desc.isInstantiable() ? desc.newInstance() : null;

我们知道desc.newInstance()就是创建对象,我读了一下这个方法的Java文档:

创建目标类的一个新的实例对象。如果该类是Externalizable类型的,则调用它自身的无参构造方法(前提是该方法是public)。如果该类是Serializable类型的,则调用该类的第一个非Serializable类型的父类的无参构造方法。

文档已经告诉我们答案了。在我们的测试代码中,Elvis实现了Serializable接口,所以反序列化的时候调用的是它父类的Object的无参构造方法创建新对象的。因此,Elvis的无参构造方法没有执行。

请看改进后的测试代码:

public class Parent {
    public Parent() {
        System.err.println("Parent no-arg constructor invoked!");
    }
}

public class Elvis extends Parent implements Serializable {

    public static final Elvis INSTANCE = new Elvis();

    public Elvis() {
        System.out.println("Elvis no-arg constructor invoked!");
    }
}

我给Elvis加了一个父类Parent,看看结果如何:

Parent no-arg constructor invoked!
Elvis no-arg constructor invoked!
===开始反序列化===
Parent no-arg constructor invoked!
elvis1与elvis2相等吗? ===> false

这下结果是符合我的预期的。父类的无参构造方法被执行了2次。第2次就是desc.newInstance()时候执行的。

通过debug我们也可以发现,我们在newInstance()方法中打个断点。如下图:

在这里插入图片描述
显而易见,代码中的cons指向的是父类的构造方法。
这下我们可以得出结论:对于实现Serializable接口的类,并不要求该类具有一个无参的构造方法, 因为在反序列化的过程中实际上是去其继承树上找到一个没有实现Serializable接口的父类(最终会找到Object),然后构造该类的对象,再逐层往下的去设置各个可以反序列化的属性(也就是没有被transient修饰的非静态属性)。

参考

单例与序列化的那些事儿

Java对象的序列化与反序列化

Excel COUNTIF函数精确统计全解析:从模糊匹配到精准计数 在数据处理与办公自动化领域,条件计数是数据分析的基础操作,其核心原理在于对特定范围内满足设定条件的单元格进行识别与汇总。Excel中的COUNTIF函数是实现这一功能的常用工具,它通过文本匹配逻辑与通配符机制来执行条件判断。然而,其默认的模糊匹配行为常导致统计结果偏离预期,这正是精确统计的技术价值所在——确保数据汇总的准确性与可靠性,直接影响业务报告、薪酬核算、销售分析等应用场景的决策质量。本文聚焦COUNTIF函数的精确匹配技巧,深入剖析通配符(如星号*和问号?)的转义使用(通过波浪号~),并针对大小写敏 阅读详情

相关推荐

提升仿真效率:Synopsys VCS高级编译选项优化技巧(2023最新版)

本文深入探讨了Synopsys VCS 2023版本中的高级编译选项优化技巧,帮助工程师提升仿真效率。通过并行编译、智能代码分析、精准覆盖率采样等策略,结合真实案例展示如何显著缩短仿真周期并优化资源使用,适用于数字芯片验证和大型SoC设计。

weixin_30338481的博客 113

JAVA基础-String对象类的常用方法和应用

字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串

0 680

STM32 ADC精准采集12V电池电压:从分压电路到软件校准全解析

本文详细解析了STM32 ADC精准采集12V电池电压的全过程,涵盖分压电路设计、电阻选型、ADC配置优化及软件校准方法。针对电池电压监测中的噪声、温漂等挑战,提供了硬件滤波与软件过采样等实战技巧,确保测量精度达到1%以内,满足嵌入式设备对电源管理的严苛要求。

tech5的博客 1012

Java创建对象的方式——反序列化创建对象

目录Java创建对象的几种方式反序列化创建对象思路代码示例 Java创建对象的几种方式 Java创建对象的方式共有4种。分别为: 1、通过new语句实例化一个对象。 2、通过反射机制创建对象。 3、通过clone()方法创建一个对象。 4、通过反序列化的方式创建对象。 思考:反序列化是怎么创建对象的呢? 反序列化创建对象 思路 反序列化创建对象的过程,需要将流转换为对象。那么,可以通过序列化,将对象的状态写在流里面,根据需要把该流读取出来重新构造一个相同的对象。 代码示例 首先创建一个Car类实现Seria

weixin_36894490的博客 4751

数电实训:万年历

万年历

Lmyccq的博客 1万+

华大HC32F460RS485通信实验

华大HC32F460RS485通信实验

ZhuoWuKeJi的博客 1798

java序列化与反序列化(5)------反序列化时对象的创建方式

我在前四篇文章都讲了和序列化相关的东西,在第四篇文章中讲了通过实现Serializable,Cloneable这两个接口来实现深拷贝,但是一直有一个问题值得再讨论一下那就是:反序列化时对象是怎么创建的? 在第四篇文章中我们看到,不管通过实现Cloneable接口还是Serializable来进行深拷贝创建新对象时,都没有调用任何的构造函数进行创建对象,这看起来好像是jvm直接操作内存创建了对象。 我们知道java中创建对象的方式有如下三种: 通过new关键字创建对象,这个过程一定是需要调用构造函数的 反射C

远方和诗 的博客 5004

基于Codex平台与AI Agent技能开发,实现抖音爆款视频分析与脚本自动生成

大家好,我是专注于AI应用开发的技术博主。最近在探索如何利用AI工具自动化内容创作时,我发现了一个非常有趣的组合:通过Codex平台创建自定义的Skill(技能),来批量分析抖音平台的爆款视频,并基于分析结果自动生成新的带货视频脚本。这听起来像是内容团队的“黑科技”,但实现起来其实有清晰的路径可循。本文将为你完整拆解这个实战项目,从环境搭建、Skill编写、数据抓取到视频脚本生成,手把手教你打造自己的“AI内容助理”。无论你是想了解AI Agent的开发,还是对短视频自动化创作感兴趣,都能从本文中获得可直接

weixin_34110749的博客 644

如何序列化和反序列化一个java对象

首先,什么是序列化? 序列化,目前已经得到大多数计算机语言的支持,Java也不例外,Java的序列化功能是作为I/O功能的一个子项,它的使用也是比较方便的;序列化,又称为“串化”,可以形象的把它理解为把java对象内存中的数据采编成一串二进制的数据,然后把这些数据存放在可以持久的数据存储设备,如磁盘。当需要还原这些数据的时候,再通过反序列化的过程,把对象又重新还原到内存中。

木凡_Denius 1192

2.1 直流无刷电机(BLDC):机械结构与组件

本文详细解析了直流无刷电机(BLDC)的机械结构与核心组件。BLDC电机通过电子换向取代传统机械电刷,主要包含定子、转子、位置传感器和电子换向器四大组件。定子采用硅钢片叠压结构,配有三相绕组;转子采用永磁体材料,结构设计影响转矩特性;位置传感器(霍尔、编码器、旋转变压器)实现精准换向;电子换向器通过功率逆变拓扑完成电流控制。文章还对比了不同绕组类型、永磁材料及传感器技术的性能特点,为BLDC电机的设计与应用提供了理论基础。

技术工作者 387

ArcGIS实验教程——实验十七:缓冲区分析(Buffer Analysis)

【实验描述】缓冲区(Buffer)是为了识别某一地理实体对周围地物的影响而在其周围建立的一定宽度多边形区域,缓冲区分析(Buffer Analysis)是用来确定不同地理要素的空间临近性或接近程度的一种分析方法。作为GIS的空间分析方法之一,缓冲区分析的应用范围特别广泛,常用于分析矢量实体对周围的影响。例如,工厂排放的废水废气所影响的空间范围等等。 一、缓冲区的基本概念 1、缓冲区 是地理空间目标的一种影响范围或服务范围。 2、缓冲区分析 指根据分析对象的点、线、面实体,自动建立它们周围一定距离的带

智慧空间实验室 1万+

Java对象的序列化和反序列化

参与序列化和反序列化的对象,必须实现Serializable接口,没有实现该接口时,报错“NotSerializableException”但该接口中什么代码也没有,它只是一个标识,标识给JVM看的。一次序列化多个对象时,参与序列化的ArrayList集合以及集合中的对象User都需要实现“java.io.Serializable”ArrayList源码中已经实现了Serializable接口。如果不指定版本号,当代码后期有修改,修改之后再重新编译就会由如下报错,提示序列化版本不一致。

flytalei的博客 1712

使用MCAL的Fee模块集成ETAS存储协议栈

由于ETAS Fee模块导致初始化时间较长,且集成占用的内存较大,所以最终考虑使用MCAL中的Fee模块来集成ETAS的Nvm模块,本文介绍具体的集成方法注意:本文所涉及的集成前提是原有的ETAS协议栈已正常使用使用IFX Fee需要手动配置Fee,可能有出错的风险,最好是利用脚本自动生成代码来实现。另外,需要注意IFX的Fee中block数据没有CRC校验,如果使用该Fee,建议Nvm中加CRC校验(ETAS Fee中block自带CRC,可以不需要Nvm Crc),防止数据被意外篡改导致的异常。

赞的博客 404

java 反序列化 构造函数_Java反序列化创建对象探析

通过反序列化生成对象的过程主要由以下几个步骤:1、创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;2、 通过对象输入流的readObject()方法读取对象。其中正是readObject方法返回了一个对象,这个对象就是根据序列化生成的文件而创建的对象,所以反序列化如何创建对象关键就在于readObject方法的实现,那就来探析一下它的实现,它的源码如下:public final...

weixin_39626089的博客 305

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Java对象创建全解:从new到反序列化的多种核心方式

在Java中,"万物皆对象"的核心理念贯穿始终。理解对象创建方式是掌握Java编程的关键,本文将系统梳理几种对象创建方式,涵盖常规用法、反射、克隆等进阶技巧,并深入分析其底层机制与适用场景。

不会说话の猴子的博客 623

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java 创建对象的四种方法:new;反射;克隆;反序列化

Java 创建对象的四种方法:new;反射;克隆;反序列化

weixin_44553952的博客 544

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

java原生序列化中反序列化时,是如何创建对象的

看一下源代码 生成对象的 private Object readOrdinaryObject(boolean unshared) throws IOException { ... obj = desc.isInstantiable() ? desc.newInstance() : null; ... ...

dajiajia2015的博客 909

编程自学指南:java程序设计开发,Java 对象创建的6种方式,从new到反射:Java 对象创建全解析,new关键字,反射机制,克隆(Clone),反序列化 ,工厂模式,建造者模式

编程自学指南:java程序设计开发,Java 对象创建的6种方式,从new到反射:Java 对象创建全解析,new关键字,反射机制,克隆(Clone),反序列化 ,工厂模式,建造者模式

zl515035644的博客 1992

Java创建对象的四种方式new、反射、clone、序列化与反序列化

Java中创建对象的四种方式 用new语句创建对象,这是最常见的创建对象的方法。 User user = new User(); 运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。 通过反射来生成对象有如下两种方式: ①使用Class对象的newInstance()方法来创建该Class对象对应类的实例。但是这种方式要求该Class对象的对应类有默认的构造器,而执行newInstance()方法时实际

qq_40050233的博客 1662

java 序列化 构造函数_Java反序列化时是否通过默认构造函数创建对象?

问题背景今天在解决一个对象的持久化问题时,需要用到序列化技术。一开始,我想用 fastjson,但是麻烦的是这个框架是基于 getter 方法来序列化对象的,可是我序列化的对象不是一个标准的 Java Bean 对象,没有 getter/setter 方法。而我的需求是根据字段(类成员变量)来序列化对象。然后我就想到了使用 Java 序列化技术,并且配合使用 transient 屏蔽不需要参与序列...

weixin_42522857的博客 462

【每日Java】IO高级流知识点:对象输入输出流的创建与运用(将对象的序列化与反序列化打包成工具类)

前言: 在Java中,高级流的构造必须基于低级流之上,也就是说在构造高级流对象时,必须进行传入低级流对象参数的有参构造。 实现目标: 运用对象输入输出流来实现将对象读写到本地文件中。 本地文件: 源码与解释: 运行结果: 写入到本地文件: 从本地文件中读取: 注意事项: 将对象写入本地文件中的操作也称为对象的序列化,而将本地文件中的对象读入到虚拟机被称为对象的反序列化。 所以操作的对象必须能被序列化和反序列化。 在Java中,接口定义了一系列意义特殊的静态

qq_41891566的博客 440

Java进阶(4)——结合类加载JVM的过程理解创建对象的几种方式:new,反射Class,克隆clone(拷贝),序列化反序列化

1.类什么时候被加载到JVM中,new,Class.forName: Class.forName(“包名.类名”); 2.创建对象的方式,反射,本质是获得类的类对象Class; 3.克隆clone,深拷贝,浅拷贝的对比; 4.序列化和反序列化的方式;

Arya的博客,专注后端领域 1270

java创建对象new后面为啥可以传入参数_java反序列化——apacheshiro复现分析

看了好久的文章才开始分析调试java的cc链,这个链算是java反序列化漏洞里的基础了。分析调试的shiro也是直接使用了cc链。首先先了解一些java的反射机制。一、什么是反射:反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行的时候才动态加载类,并且对于任意一个类,都能够知道这个类的所有属性和方法,调用方法/访问属性,不需要提前在编译期知道运行的对象是谁,他允...

weixin_39839541的博客 255

Java 创建对象的五种方式

我们日常生活中会创建很多对象,但是这个对象和你理解的那么对象不一样,因为作者不是女娲,不能造人。作者只是程序员,他只能在 Java 中创建对象。那么我问你一个问题,你知道 Java 中如何创建对象吗?这个问题仿佛是给 Java 新手来写的,好像有点瞧不起在座各位的样子,嗯。。。那么我换种问法好了,毕竟看我公众号的人都是将来月入 10w 的大佬。你知道 Java 中有哪几种创建对象的方式吗?诶?这个问题有点意思,平常我们用的最多的就是使用new来创建对象了,这是第一种方式;

白话机器学习 1215

什么是创建对象java_java创建对象的几种方式分别是什么

java创建对象有五种方式,分别是:1、使用new关键字这是最常见也是最简单的创建对象的方式。通过这种方式,我们可以调用任意的构造函数(无参的和带参数的)。Employee emp1 = new Employee();2、使用Class类的newInstance方法这个newInstance方法调用无参的构造函数创建对象。我们可以通过下面方式调用newInstance方法创建对象:Employee...

weixin_28676289的博客 1252

Java创建对象的几种方式

Java创建有四种方式: (1)用new 语句创建对象,这是最常用的创建对象方法。 (2)运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。 (3)调用对象的clone()方法 (4)运用fan

dan_smile 1万+
上一篇: ZooKeeper节点数据量限制引起的Hadoop YARN ResourceManager崩溃原因分析(三)
下一篇: Redis AOF重写阻塞问题分析
Viking_bird
博客等级 码龄11年 92粉丝 183原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值