谁能告诉我Java中对序列化的需求是什么,并给我一个示例场景来说明需求?(我已经了解了什么是序列化,我只想了解何时使用它)。
Answers:
通常在需要通过网络发送数据或存储在文件中时使用序列化。数据是对象,而不是文本。
现在的问题是您的网络基础结构和硬盘是可以理解位和字节但不能理解JAVA对象的硬件组件。
序列化是将Java对象的值/状态转换为字节,以通过网络发送或保存它。
这类似于通过PSTN电话线传输语音的方式。
有关序列化的简短故事
经过多年的努力,地球的科学家开发了一种可以帮助他们进行日常工作的机器人。但是,该机器人的功能要比火星科学家开发的机器人要少。
在两颗行星的科学家举行会议之后,决定火星将其机器人运送到地球。但是出现了问题。向地球发送100个机器人的成本为1亿美元。大约需要60天的旅行时间。
最后,火星的科学家决定与地球的科学家分享他们的秘密。这个秘密是关于类/机器人的结构的。地球科学家在地球本身上开发了相同的结构。火星的科学家序列化了每个机器人的数据,并将其发送到地球。地球的科学家对数据进行反序列化,然后将其相应地输入到每个机器人中。
此过程为他们节省了交流大量数据的时间。
一些机器人被用于火星的防御工作。因此,他们的科学家将这些机器人的一些关键特性标记为瞬态,然后才将其数据发送到地球。请注意,对象反序列化时,transient属性设置为null(在引用的情况下)或默认值(在基本类型的情况下)。
地球科学家注意到的另一点是,火星科学家要求他们创建一些静态变量以保留有关环境的详细信息。这些详细信息由某些机器人使用。但是火星的科学家们并没有分享这些细节。因为地球的环境不同于火星的环境。
即使了解机器人的类结构并序列化了数据,地球科学家仍然无法反序列化使机器人工作的数据。
Exception in thread "main" java.io.InvalidClassException:
SerializeMe; local class incompatible: stream classdesc
:
火星的科学家们正在等待全部付款。付款完成后,火星的科学家与地球的科学家共享了serialversionUID。地球的科学家将其设置为机器人课程,一切开始起作用。
更新资料
尽管借助序列化,他们开始能够使用信号而不是实际的太空飞船发送数据,但他们意识到发送大量数据仍然是一个挑战。序列化使该过程更便宜,更快,但是仍然很慢。因此,不同的科学家提出了不同的想法来减小数据量。一些科学家建议压缩数据,另一些科学家建议使用不同的机制来表示它,以便可以将其反序列化。其中的一些想法是XML,JSON,msgpack,निम्न(Nimn)
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的开源协议缓冲区和MessagePack是序列化库/格式的示例,可让您读取/写入紧凑的二进制数据并轻松维护版本兼容性。这些库相对于内置Java序列化的最大缺点是,它们涉及用于序列化的纯旧数据对象(与功能也与之关联的功能更全的Java对象相对);但是,实际上,这种缺点是一个优点,因为将信息存储所来自/从的数据模型与包装对象或从包装对象派生的对象分离开实际上是一种良好的编程习惯,并且可以轻松支持多种格式。
用法
由于您不仅需要定义,还需要其他需求,因此有许多用例:
只需保存您的数据以备后用。例如,假设您正在编写视频游戏。您的程序不会永远运行;即使它永远不会崩溃(希望如此),您的用户也可能会在某个时候退出程序,或者操作系统可能会杀死程序以节省资源(例如,在Android上,用户未与之交互的后台进程经常并被操作系统故意杀死,以回收RAM等系统资源。为了确保用户不会从头开始,而是可以从他们所在的位置或从最近的保存点开始恢复,您需要将游戏状态写入持久性存储(例如,硬盘,用户的Google云端硬盘帐户等)。为此,
从远程服务器检索信息。让我们继续游戏示例...假设您正在创建在线多人游戏,或者希望在用户不更新其应用程序的情况下提供新的关卡或项目。为此,您希望从服务器计算机传达有关在线播放器的信息或有关新级别/项目的信息(您可以将其用作在各种设备上安装的所有应用程序副本的联系点)到应用程序的各个副本。服务器和应用程序都需要这些数据结构的某种内存表示形式(例如,其他玩家的位置,新关卡的结构,新物品的描述/图像等),但是要传递信息从服务器到设备上的应用,
在两个不同进程/应用程序之间或应用程序与某个存储系统之间的几乎任何通信都是需要某种序列化机制的情况。
您还可以使用序列化实现对象克隆
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;
}
}