在 Java 中序列化的需要是什么?

有人能告诉我 Java 中序列化的需求是什么,并给我一个示例场景来解释这个需求吗?(我已经知道什么是序列化了,我只是想知道你什么时候会用到它)。

82018 次浏览

当您希望将对象的状态保存到文件中或通过网络发送时,需要将其转换为一系列字节。这就是所谓的序列化。

Java 有一个内置的机制,其他选项包括 XML 或 JSON。

例如: 缓存对象、进行远程方法调用、将对象图保存到磁盘。

  • 如果你想在磁盘上存储一个对象(- 结构) ,你需要序列化。
  • 在传输对象之前,webservice 需要将对象序列化为 xml。

当需要通过网络发送数据或存储在文件中时,通常使用序列化。我说的数据是指对象而不是文本。

现在的问题是,您的网络基础设施和硬盘是硬件组件,它们能够理解位和字节,但不能理解 JAVA 对象。

序列化是将 Java 对象的值/状态转换为字节以通过网络发送或保存它。

这类似于你的声音是如何通过 PSTN 电话线传输的。

Java 序列化(特别是 可序列化可体验的接口)允许您读/写任意复杂的 Java 对象,自动或手动地从/到磁盘或从/到网络。XML 和 JSON 是文本格式,而 Java 序列化是二进制格式。(序列化也是一个简单读/写数据的一般概念,但是因为问题是关于 Java 的,我假设您指的是内置的序列化系统,即 Serializer/Exernalable)

与 XML/JSON 相比,“实现可序列化”的优势
首先,您几乎可以免费获得序列化。您不需要对您的对象进行太多的更改,就可以让序列化机制使用它。另一个优点是,因为它是二进制格式,所以比文本格式紧凑得多,因此可能会使用更少的空间(这有利于节省网络带宽或磁盘上的存储空间)。

与 XML/JSON 相比,“实现可序列化”的缺点
内置 Java 序列化的缺点是,如果对对象进行更改,那么使不同的序列化格式兼容真的会是一场噩梦。另外,虽然可以手动编辑 XML 和 JSON,但是不能编辑序列化的 Java 对象(不将其读入 Java)。出于同样的原因,调试 XML 和 JSON 通常比调试二进制格式更容易,因为 XML 和 JSON 是可读的。Java 的内置序列化机制的另一个缺点是,您不能(容易地)从另一种编程语言序列化/反序列化数据。

读/写数据的替代技术
除了 Java 的内建序列化之外,还有其他可供选择的序列化技术,这些技术可以让你两全其美: 紧凑的二进制格式、语言互操作、易于版本兼容性,以及经常使用的调试工具,这些工具使得以可读格式转储二进制数据变得非常容易。例如,Google 的开源 协议缓冲信息包就是序列化库/格式的例子,它们可以让你读/写紧凑的二进制数据并轻松地保持版本兼容性。相对于内置 Java 序列化,这些库最大的缺点是它们涉及到用于序列化的普通旧数据对象(而不是功能更全面的 Java 对象,后者也有与之相关的行为) ; 然而,这个缺点实际上是一个优点,因为将信息存储的数据模型与包装或派生信息的对象分离开来,实际上是一个很好的编程实践,并且更容易支持多种格式。

用法
因为您要求的是需要,而不仅仅是定义,所以有许多用例:

  1. 只需保存数据供以后使用。例如,假设您正在编写一个视频游戏。你的程序不会永远运行; 即使它永远不会崩溃(希望如此) ,你的用户可能会在某个时候退出程序,或者操作系统可能会为了节省资源而杀死程序(例如,在 Android 上,用户没有交互的后台进程经常被操作系统故意杀死,以回收系统资源,比如 RAM)。为了确保用户不是从一开始就开始,而是从他们在的地方或者最近的保存点恢复,你需要把游戏的状态写到持久存储(比如硬盘,用户的 Google Drive 帐号等等)。为此,需要将内存中表示游戏状态的数据结构转换为可写入磁盘(或者保存数据的任何系统)的原始字节。

  2. 从远程服务器检索信息。让我们继续游戏的例子... 假设你正在创建一个在线多人游戏,或者你希望在不更新用户应用程序的情况下提供新的关卡或项目。要做到这一点,你需要有关在线播放器的信息,或者有关新级别/项目的信息从一台服务器计算机(你使用它作为联系点的所有副本的应用程序安装在各种设备上)传达到应用程序的各个副本。服务器和应用程序都需要这些数据结构的某种内存表示(例如,其他玩家的位置,一个新级别的结构,一个新项目的描述/图像,等等) ,但是要将信息从服务器传输到设备上的应用程序,通信系统由原始字节组成,因此有必要有一种方法来将数据转换为原始字节,并将原始字节转换回一个有意义的内存数据结构。

在两个不同的进程/应用程序之间,或者应用程序与某个存储系统之间,几乎所有的通信都需要某种序列化机制。

关于序列化的短篇小说

经过多年的艰苦工作,地球上的科学家们开发出了一种可以帮助他们日常工作的机器人。但是这个机器人比火星科学家开发的机器人具有更少的功能。

经过两个行星科学家的会晤,决定火星将把他们的机器人送到地球。但问题出现了。将100个机器人送到地球的成本是1亿美元。大约需要60天的行程。

最终,火星的科学家们决定与地球的科学家们分享他们的秘密。这个秘密是关于类/机器人的结构。地球上的科学家在地球上发展出了同样的结构。火星科学家对每个机器人的数据进行 连载并将其发送到地球。地球上的科学家 反序列化了的数据,并反馈给每个机器人相应。

这个过程节省了他们传递大量数据的时间。

一些机器人被用于火星上的一些防御工作。因此,他们的科学家在向地球发送数据之前,将这些机器人的一些关键性能标记为 暂时的。注意,当对象被反序列化时,瞬态属性设置为 null (在引用情况下)或默认值(在基元类型情况下)。

地球科学家注意到的另一点是,火星科学家要求他们创建一些 静态变量来保存有关环境的细节。这些细节被一些机器人使用。但是火星的科学家们并不分享这些细节。因为地球的环境与火星的环境不同。

即使了解了机器人的类结构和序列化数据,地球的科学家也不能反序列化数据,这些数据可以使机器人工作。

Exception in thread "main" java.io.InvalidClassException:
SerializeMe; local class incompatible: stream classdesc
:

火星的科学家们正在等待全额付款。一旦付款完成,火星的科学家们就与地球的科学家们分享了这个系列版本的 UID。地球的科学家把它设定为机器人类,一切都开始工作了。

更新

虽然在序列化的帮助下,他们能够用信号代替实际的宇宙飞船来发送数据,但是他们意识到发送大量的数据仍然是一个挑战。序列化使处理过程更便宜、更快,但仍然很慢。因此,不同的科学家提出了不同的想法,以减少数据的大小。一些科学家建议压缩数据,一些科学家建议使用不同的机制来表示它,这样它就可以反序列化回来。一些想法是 XMLJSONMsgpack译自: 美国《科学》杂志网站(http://github.com/nimndata/spec)原著: http://github.com/nimndata/spec

还可以使用序列化实现对象克隆

序列化通常指把 Object 转换成一系列的位。这是一个重要的 Java,因为 Java 主要意味着基于网络的应用程序的我的意思是使数据可以通过网络

public class Serializer {


public static void write(Object o, File f) throws IOException {
f.delete();
f.createNewFile();
FileOutputStream fileOut = new FileOutputStream(f);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(o);
out.close();
fileOut.close();
}


public static Object read(File f) throws Exception{
FileInputStream fileIn = new FileInputStream(f);
ObjectInputStream in = new ObjectInputStream(fileIn);
Object e = in.readObject();
in.close();
fileIn.close();
return e;
}


public static byte[] toBytes(Object o) {
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(o);
out.flush();
bytes = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}


return bytes;
}


public static Object fromBytes(byte[] bytes) {
Object o = null;
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInput in = null;
try {
in = new ObjectInputStream(bis);
o = in.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
// ignore close exception
}
}


return o;
}
}

当从一个类向另一个类发送数据时出现问题时,需要序列化。 其他类位于不同的位置或硬盘上,例如在分布式系统中

序列化的反向操作称为反序列化

默认情况下,字符串类和所有包装类实现可序列化接口

可序列化接口也是标记接口,它为类提供了序列化功能。因此,如果我们想通过网络发送对象的状态,我们应该实现一个可序列化的接口