【发布时间】:2011-01-29 08:19:53
【问题描述】:
谁能告诉我 Java 中的序列化需要什么,并给我一个示例场景来解释需要吗? (我已经明白什么是序列化了,我只是想了解你什么时候使用它)。
【问题讨论】:
-
在序列化中,重点不是将对象转换为位和字节,对象已经是位和字节。序列化是使对象的“状态”持久化的过程。阅读:stackoverflow.com/a/69416269/9868445
标签: java
谁能告诉我 Java 中的序列化需要什么,并给我一个示例场景来解释需要吗? (我已经明白什么是序列化了,我只是想了解你什么时候使用它)。
【问题讨论】:
标签: java
关于序列化的小故事
经过多年的努力,地球上的科学家们开发了一种可以帮助他们完成日常工作的机器人。但这个机器人的功能比火星上的科学家开发的机器人少。
在两颗行星的科学家会面后,决定火星将他们的机器人送到地球。但是出现了问题。将 100 个机器人送到地球的成本是 1 亿美元。大约需要 60 天的旅行时间。
最后,火星的科学家决定与地球的科学家分享他们的秘密。这个秘密是关于班级/机器人的结构的。地球的科学家在地球本身上开发了相同的结构。火星的科学家序列化每个机器人的数据并将其发送到地球。地球上的科学家将数据反序列化并相应地输入每个机器人。
这个过程为他们节省了沟通大量数据的时间。
一些机器人被用于火星上的一些防御工作。因此,他们的科学家在将这些机器人的数据发送到地球之前,将这些机器人的一些关键特性标记为瞬态。请注意,当对象反序列化时,transient 属性设置为 null(在引用的情况下)或默认值(在原始类型的情况下)。
地球科学家注意到的另一点是,火星的科学家要求他们创建一些静态变量以保留有关环境的详细信息。这些细节被一些机器人使用。但火星的科学家并没有分享这些细节。因为地球的环境与火星的环境不同。
即使知道机器人类结构并拥有序列化数据,地球科学家也无法反序列化可以使机器人工作的数据。
Exception in thread "main" java.io.InvalidClassException:
SerializeMe; local class incompatible: stream classdesc
:
火星的科学家们正在等待全额付款。付款完成后,火星的科学家与地球的科学家分享了 serialversionUID。地球科学家将其设置为机器人类,一切都开始工作了。
更新
虽然在序列化的帮助下,他们能够使用信号而不是实际的飞船来发送数据,但他们意识到发送大量数据仍然是一个挑战。序列化使这个过程更便宜、更快,但它仍然很慢。因此,不同的科学家提出了不同的想法来减少数据量。一些科学家建议压缩数据,一些科学家建议使用不同的机制来表示它,以便可以反序列化回来。一些想法是XML、JSON、msgpack、निम्न (Nimn)
【讨论】:
当需要通过网络发送数据或存储在文件中时,通常会使用序列化。我所说的数据是指对象而不是文本。
现在的问题是您的网络基础设施和硬盘是理解位和字节但不理解 JAVA 对象的硬件组件。
序列化是将 Java 对象的值/状态转换为字节以通过网络发送或保存。
这类似于您的声音通过 PSTN 电话线传输的方式。
【讨论】:
Java 序列化(特别是Serializable 和Exernalizable 接口)允许您自动或手动从/向磁盘或从/向网络读取/写入任意复杂的Java 对象。 XML 和 JSON 是文本格式,而 Java 序列化是二进制格式。 (序列化也是简单读/写数据的一般概念,但由于问题是关于Java的,我假设您指的是内置的序列化系统,即Serializable/Exernalizable)
“实现可序列化”相对于 XML/JSON 的优势
起初,您几乎可以免费获得序列化。您无需对对象进行太多更改即可让序列化机制使用它。另一个优点是,因为它是二进制格式,它比文本格式更紧凑,因此可能会使用更少的空间(这有利于节省网络带宽或节省磁盘上的存储空间)。
在 XML/JSON 上“实现可序列化”的缺点
内置 Java 序列化的缺点是,如果您对对象进行更改,使不同的序列化格式兼容可能真的是一场噩梦。此外,虽然您可以手动编辑 XML 和 JSON,但您不能编辑序列化的 Java 对象(不将其读入 Java)。出于同样的原因,调试 XML 和 JSON 通常比调试二进制格式更容易,因为 XML 和 JSON 是人类可读的。 Java 内置序列化机制的另一个缺点是您不能(轻松)序列化/反序列化来自其他编程语言的数据。
读取/写入数据的替代技术
除了 Java 的内置序列化之外,还有其他序列化技术可以为您提供两全其美的优势:紧凑的二进制格式、语言互操作、易于版本兼容性,以及通常的调试工具,可以轻松地将二进制数据转储为可读格式。例如,Google 的开源 protocol buffers 和 MessagePack 是序列化库/格式的示例,可让您读取/写入紧凑的二进制数据并轻松维护版本兼容性。这些库相对于内置 Java 序列化的最大缺点是它们涉及用于序列化的普通旧数据对象(与功能更全的 Java 对象相反,它们也具有与之相关的行为);然而,这个缺点实际上是一个优点,因为将存储信息的数据模型与包装或派生它们的对象分开实际上是一种良好的编程实践,并且更容易支持多种格式。
用法
由于您询问了需求,而不仅仅是定义,因此有许多用例:
只需保存数据以供以后使用。例如,假设您正在编写一个视频游戏。你的程序不会永远运行;即使它永远不会崩溃(希望是这种情况),您的用户可能会在某个时候退出程序,或者操作系统可能会终止程序以节省资源(例如,在 Android 上,用户不与之交互的后台进程很频繁并被操作系统故意杀死以回收 RAM 等系统资源)。为了确保用户不会从一开始就开始,而是可以从他们所在的位置或最近的保存点恢复,您需要将游戏的状态写入持久存储(即硬盘驱动器,用户的 Google Drive 帐户等)。为此,您需要将内存中表示游戏状态的数据结构转换为可以写入磁盘(或保存数据的任何系统)的原始字节。
从远程服务器检索信息。让我们继续游戏示例……假设您正在创建一个在线多人游戏,或者您希望在用户不更新其应用程序的情况下在游戏中提供新的关卡或物品。为此,您需要从服务器计算机(您将其用作安装在各种设备上的所有应用程序副本的联系点)传达有关在线播放器的信息或有关新级别/项目的信息到应用程序的各个副本。服务器和应用程序都需要这些数据结构的某种内存表示(例如,其他玩家的位置、新关卡的结构、新项目的描述/图像等),但要传输信息从服务器到设备上的应用程序,通信系统由原始字节组成,因此有必要将数据转换为原始字节,并将原始字节转换回有意义的内存数据结构。
几乎任何两个不同进程/应用程序之间或一个应用程序与某个存储系统之间的通信都需要某种序列化机制。
【讨论】:
当您想将对象的状态保存到文件中或通过网络发送时,您需要将其转换为一系列字节。这称为序列化。
Java 有一个内置机制,其他选项包括 XML 或 JSON。
需要时的示例:缓存对象、进行远程方法调用、将对象图保存到磁盘。
【讨论】:
【讨论】:
你还可以使用序列化实现对象克隆
【讨论】:
序列化通常称为将对象转换为位序列。它是 java 中必不可少的一个,因为 java 主要用于基于 Web 的应用程序,我的意思是使数据在网络上可用
【讨论】:
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;
}
}
【讨论】:
当将数据从一个类发送到另一个类时出现问题时,需要进行序列化。 另一个类在不同的位置或硬盘上。即在分布式系统中
序列化的逆操作称为反序列化
String 类和所有包装类默认实现可序列化接口
Serializable 接口也是标记接口,它为您的类提供序列化功能。因此,如果我们想通过网络发送对象的状态,我们应该实现一个可序列化的接口
【讨论】: