序列化和普通对象存储之间的区别是什么?

4

序列化是将存储在内存中的对象转换为字节流,以便于在网络上传输、存储在数据库中等操作。

但是,对象不是已经以位和字节的形式存储在内存中了吗?为什么我们需要另一个过程将以字节表示的对象转换为另一种字节表示形式?难道我们不能直接通过网络传输对象吗?

我认为我可能对对象存储方式或访问对象字段的方式有所疏漏。

请有人帮助我澄清这个困惑吗?

4个回答

8
不同的系统在内存中存储数据的方式不同,其中一个明显的例子是字节序问题。
序列化定义了一种方式,使得使用不同内存表示的系统可以进行通信。
另一个重要的事实是,内存和序列化数据的需求可能不同:在内存中,需要快速读取(也许是写入);而在序列化时,需要小的尺寸。比起创建一个适用于两种情况的格式,创建两个不同的格式更加容易。
一个例子是LinkedHashMap:在内存中,它基本上存储了两个版本的映射(一个用来捕获插入顺序;一个作为传统哈希映射)。然而,在序列化形式中,你不需要这两个表示来重构相同的映射:你只需要键/值对的插入顺序。因此,序列化形式不会存储与内存形式相同的数据。

那么,所有编程语言中的序列化算法都是以相同的方式实现的吗?例如,Java和C#中的序列化库将以相同的方式工作,将对象转换为相同的端字节顺序吗?那么序列化是否有一个标准呢? - chaudharyp
有几种用于序列化的标准,例如看一下JSON或XML。 - Florian Moser
没有一种单一的序列化数据的方式。即使在同一种语言中,序列化相同数据的方式也可能有很多种;Java内置的序列化(指实现Serializable接口的类)只是其中一种方法。 - Andy Turner
我现在明白了区别。我曾经(真傻!)认为序列化对象后得到的字节流也是以某种字节序形式存在的。但是,那个流只是对象的简单字节表示。它取决于终端系统如何存储这些字节(大端或小端)。字节序在内存分配时才会出现。感谢@AndyTurner! - chaudharyp
1
@chaudharyp 是的,但请不要认为我的答案仅限于字节顺序。它可以包括其他事情,比如字段对齐,即在内存中填充结构以实现更快的访问。 - Andy Turner

2
序列化将内存中现有的字节转换为通用形式。
这样做是因为不同的系统以不同的方式分配内存。因此,我们不能确保对象可以直接从一台机器的内存保存,然后正确地加载到另一台不同的机器上。
您可以在Oracle文档的此页面上找到更多信息。

1

这是《Java编程思想》一书中关于对象序列化的解释。

当您创建一个对象时,它存在的时间与您需要它的时间一样长,但在程序终止时,它不会存在。虽然这起初是有道理的,但在某些情况下,如果一个对象能够在程序没有运行时存在并保存其信息,那将非常有用。然后,下次启动程序时,该对象将存在,并且具有与上次运行程序时相同的信息。当然,您可以通过将信息写入文件或数据库来获得类似的效果,但为了使所有内容都成为对象,声明一个对象为“持久性”,并且让所有细节得到处理会非常方便。
Java的对象序列化允许您将实现Serializable接口的任何对象转换为字节序列,稍后可以完全恢复以重新生成原始对象。这甚至适用于网络,这意味着序列化机制自动补偿操作系统之间的差异。也就是说,您可以在Windows机器上创建一个对象,对其进行序列化,然后将其发送到Unix机器上,在那里正确重建它。您不必担心不同机器上的数据表示、字节顺序或任何其他细节。
希望这可以帮助您。

0

让我们以这种思维方式进行:我们按原样接收对象,并将其作为字节数组通过网络发送。另一个套接字/httphandler接收该字节数组。

现在,有两件事情值得考虑:

  1. 要发送多少字节?
  2. 这些字节是什么?这些字节代表哪个类?

您还需要提供此数据。因此,仅针对此操作,我们需要额外的两个步骤。

现在,在C#和Java中,与C ++相反,对象分散在堆中,每个对象保存对它包含的对象的引用,因此现在我们有另一个要求

  1. 递归“捕获”所有内部对象并将它们打包到字节数组中

现在,我们得到了打包的字节数组,它表示某个对象层次结构,我们需要告诉另一侧如何将此字节数组解包回对象+它持有的对象

  1. 发送有关如何解包该字节数组的信息以获取对象层次结构

一些实体无法通过网络发送,例如函数。所以现在我们有了另一个步骤

  1. 去除无法序列化的内容,如函数

这个过程会不断地进行,对于每个新的解决方案,你都会遇到很多问题。序列化是将你所谈论的字节数组转换为可以在其他环境中处理的内容,比如网络/文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接