什么是对象序列化?

发布于 2024-07-11 13:14:48 字数 35 浏览 8 评论 0 原文

“对象序列化”是什么意思? 您能用一些例子解释一下吗?

What is meant by "object serialization"? Can you please explain it with some examples?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

棒棒糖 2024-07-18 13:14:51

序列化是通过将对象的特定状态转换为字节码来保存对象的过程。 此转换后的字节码用于在 2 个 JVM 之间传输对象状态,其中接收 JVM 反序列化字节码以检索共享对象的状态。
序列化和反序列化是使用serialVersionUID作为所涉及的JVMS中的参考来完成的。

在 Java 中,使用序列化和外部化接口可以实现相同的效果

Serialization is a process of saving the specific state of an object by converting it into byte code. This converted byte code is used to transfer object states between 2 JVM where the receiving JVM deserialises the bytecode to retrieve the state of the object that was shared.
The serialization and de-serialization is done using serialVersionUID as reference in JVMS involved.

In Java the same is achieved using Serialization and Externalisation interfaces

海未深 2024-07-18 13:14:51

因此,这里的大多数答案都倾向于序列化是如何完成的,而不是为什么。 你必须知道,尽管在 OOP 语言开始给它一个听起来很酷的名字之后,术语“序列化”或“编组”开始出现在技术术语中(特别是当互联网出现并且我们需要通过串行网络逐字节发送时。)这个过程从晶体管发明的第一天起,计算机就一直存在。

那么为什么要序列化呢?
要了解这一点,您需要回到过去。 基本思想来自C语言,冯·诺伊曼模型长期和短期记忆之间的差异(哦,我们按照我们自己的大脑设计我们的金属婴儿不是吗!)以及堆栈和堆的记忆模型。

从历史上看,我们一直拥有良好/大型的长期存储机制。 例如磁带、旋转硬盘——数据连续存储,即一堆相继存储的存储位置。 例如,如果它是一个磁盘,那么它就是一块连续的内存,通过铁磁性,您可以打开和关闭一些位置来分别表示 1 和 0 位。 那么为什么冯·诺依曼建议将 RAM 作为人类和硬盘之间的中间体呢? 或者为什么我们需要 RAM..? 简短的答案就在名称本身中......随机存取存储器......当然,我们总是有几乎无限的硬盘存储,但是要访问硬盘中的某些内容(例如存储),您必须一点一点地串行访问它......所以想象一下你想要的一段数据在磁盘的末尾(如果你有兴趣了解更多,请谷歌日志结构化文件系统)......以及你/CPU需要多长时间才能获取它。 简而言之,它不是随机的。所以冯·诺依曼和其他计算机科学家提出了 RAM 的想法:一个临时有限的小内存,可以随机访问。

现在,如果你用谷歌搜索 RAM 的内存模型,你会发现 RAM 由几个主要区域组成:代码区、数据区、堆栈区、堆区。 在这 4 个区域中,只有堆区域是真正随机的...其他所有区域几乎总是获得连续的内存分配。

现在,由于硬件限制,假设您是 Dennis Ritchie 设计 C。现在,如果您不知道,在 C 中,所有基本数据类型(例如 int、char、char[])等均在 RAM 的堆栈区域中初始化。 任何比基本数据类型(例如结构)复杂的数据类型都在堆中初始化,并通过堆栈区域中的指针进行访问。 所以堆是唯一真正的随机内存。

就是这样。 您只需要了解这两个基础知识即可。 此后编程语言中发生的一切都只是美化的优化。 例如,在 Java 中,当他们说“一切都在堆中初始化”时,他们的意思是,确保基本数据类型(egint)仍然在连续的堆栈区域中初始化,但维护和跟踪是一件很痛苦的事情,所以我们希望您使用我们的荣耀结构,称为 Integer 类。(虽然我们只在堆栈区域中存储它的指针)

现在您看到了基本的编码问题吧? 一方面,我们有一个可随机访问的堆内存,可以通过堆栈区域中的一些指针轻松访问它,这对于正在使用代码/想要完成一些快速计算的人来说非常容易/不耗时,但是当他当一天的工作完成后,我们仍然必须将这些随机数据存储到串行硬件中,例如旋转磁盘或磁带。 然后C在内部获取结构体的指针(准确地说,只是声明的值,而不是结构体的脚手架)将它们全部写入连续的内存中,并将其存储到硬盘中......就是这样......这就是人们的想法现在被美化地称为序列化和编组。 一旦java变得流行,它本身就成为一个单独的过程(指一切都是优化)——您可以选择使用或不使用序列化。 例如,如果您确定数据结构及其值将仅用于实时计算,并且永远不必存储到串行硬盘中,Java 说,那么您肯定不必浪费资源(例如 cpu周期、堆上的空间)使其成为可序列化的对象。 例如,考虑一些抽象数据类型(例如链表、二叉树)最终如何存储在硬盘中。 例如,二叉树在 RAM 中看起来像一棵树,但在硬盘(甚至在纸上)中,如果您只写父,子,子,分隔符,父,子,子,分隔符,您可以连续存储它。

然后,当基于互联网的通信出现时,它变得更加流行。 但从根本上来说,这就是在 REST 或 HTTP 之前(例如 CORBA)之前两个设备之间进行通信的方式。 但是为什么......记住你的通信设备(例如以前的金属电缆,或现在的光纤)是串行的......即他们喜欢一个接一个的数据......但另一端的人仍然想要重新创建以一种随机的方式,这样他就可以使用自己优化的 RAM 又名堆..

tada/就是这样/QED :-D

“真正的教学法不是片面的,它是一种积极的对话,演讲者轻轻地引导他的听众进入自我实现。”

So most of the answers here lean onto How serialization is done, more than WHY. You must know that even though the term serialization or marshalling started showing up in tech lingo after OOP languages started giving it a cool good sounding name( especially once internet showed up and we needed to send byte by byte over a serial network. ) this process has been there with computers since day 1 of invention of transistors.

So why serialization?
To understand that, you need to go back in time. The fundamental idea comes from C language, von neumman model difference between long term and short term memory (oh we design our metal babies after our own brains dont we!) and the memory model of stack and heap.

Historically we have always had good/big long term storage mechanisms. E.g magnetic tapes, spinning hard disks - where data was stored serially i.e a bunch of memory locations one after the other. For example if it was a magnetic disk, it was a chunk of contiguous memory where by ferromagnetism, you switch a few places on and off to represent 1 and 0 bits respectively. So why did von neumman suggest RAM as an intermediate between human and hard disk? or why do we even need a RAM..? Short answer is in the name itself..Random Access Memory...sure, we had almost infinite hard disk storage always, but to access something in hard disk like storage, you had to serially access it bit by bit...so imagine a piece of data you want is at the end of the disk(google log structured file system if you are interested in learning more)...and how long will it take for you/CPU to go get it. In short it wasnt RANDOM..So von neumann and other computer scientists came up with this idea of RAM : a temporary limited small memory, which is randomly accessible.

Now if you google memory model of a RAM, you will see there are a few major areas that comprise together to form a RAM: Code area, Data area, Stack area, Heap area. In these 4, only Heap area is truly random...everything else you almost always get contiguous memory allocation.

Now with this hardware limitation, imagine you are Dennis Ritchie designing C. Now if you didnt know, In C all fundamental data types (e.g. int, char, char[]) etc are initialized in the stack area of RAM. Any data type which is complex than the fundamental data type (e.g. struct) is initialized in the heap and accessed through pointers in stack area. So heap is the only truly RANDOM memory.

Thats it. You just need to know these two fundamentals. Everything that happened in programming languages after that was just glorified optimization. for Example, in Java when they say "everything is initialized in heap" what they mean is, sure the fundamental data types (e.g.int) are initialized still in the contiguous stack area, but its a pain in the ass to maintain and keep track, so we want you to use our glorified struct called Integer class.(while we store only pointers of it in the stack area)

Now you see the fundamental encoding problem right?. On one side we have a randomly accessible memory of heap, which is easily accessed through some pointers in stack area, making it really easy/not time consuming for a person who is working with the code/wants some quick calculation done, but when he is done working for the day, we still have to store this random looking data into a SERIAL hardware like Spinning disk or magnetic tape. Then C internally takes the pointers of a struct (only the declared values and not the scaffolding of struct to be precise) writes them all into a contiguous memory, and stores it into the hard disk...Thats it..that is what people glorifiedly now calls Seralization and Marshalling. Once java became popular this became a separate process itself (refer everything is an optimization )- where you can choose to use or not use serialization. For example if you know for sure that a data structure and its values are going to be used only for live calculation, and NEVER HAVE TO BE STORED INTO A SERIAL HARD DISK, Java said, sure then you dont have to waste resources (e.g cpu cycles, space on heap) making it a serializable object. For example think about how some abstract data types (e.g. Linked list, Binary tree) are finally stored in the hard disk. e.g. a Binary tree can look like a tree while in RAM, but in hard disk (or even on paper), if you just write parent, child,child, delimiter,parent, child,child, delimiter you can store it serially.

Then when internet based communication came up it became just more popular. But fundamentally this is how communication used to happen between two devices, before REST or HTTP..(e.g. CORBA). But why...remember your communication device (e.g. a metal cable earlier, or an optical fiber now) is SERIAL...i.e they like the data one after the other...But the person on the other end still wants to recreate it in a random way, so that he can use his own optimized RAM aka heap..

tada/that's it/QED :-D

"True pedagogy is not one sided, it is an active conversation where the speaker gently guides his audience into self realization."

蒗幽 2024-07-18 13:14:51

我将提供一个类比,以潜在地帮助巩固对象序列化/反序列化的概念目的/实用性。

我想象对象序列化/反序列化在尝试通过雨水渠移动对象的情况下。 该对象本质上被“分解”或序列化为自身的更多模块化版本 - 在本例中为一系列字节 - 以便有效地获得通过介质的通道。 从计算意义上来说,我们可以将字节通过雨水渠的路径视为类似于字节通过网络的路径。 我们正在改变我们的物体,以符合更理想的运输方式或格式。 序列化对象通常存储在二进制文件中,稍后可以读取、写入或两者兼而有之。

也许一旦我们的对象能够以分解的一系列字节的形式漏掉,我们可能希望将对象的表示形式作为二进制数据存储在数据库或硬盘驱动器中。 不过,主要的收获是,通过序列化/反序列化,我们可以选择让对象在序列化后保持其二进制形式,或者通过执行反序列化“检索”对象的原始形式。

I'll offer an analogy to potentially assist in solidifying the conceptual purpose/practicality of object serialization/deserialization.

I imagine object serialization/deserialization in the context of attempting to move an object through a storm drain. The object is essentially "decomposed" or serialized into more modular versions of itself - in this case, a series of bytes - in order to effectively be granted passage through a medium. In a computational sense, we could view the path traveled by the bytes through the storm drain as being akin to bytes traveling through a network. We're transmuting our object in order to conform to a more desirable mode of transportation, or format. The serialized object will typically be stored in a binary file which may later be read from, written to, or both.

Perhaps once our object is able to slip through the drain as a decomposed series of bytes, we may wish to store that representation of the object as binary data within a database or hard disk drive. The main takeaway though, is that with serialization/deserialization, we have the option to let our object remain in it's binary form after being serialized, or "retrieve" the object's original form by performing deserialization.

北音执念 2024-07-18 13:14:50

您可以将序列化视为将对象实例转换为字节序列(可能是二进制或不是二进制,具体取决于实现)的过程。

当您想要通过网络传输一个对象数据(例如从一个 JVM 到另一个 JVM)时,它非常有用。

在Java中,序列化机制内置于平台中,但是您需要实现Serialized接口才能使对象可序列化。

您还可以通过将属性标记为瞬态来防止对象中的某些数据被序列化。

最后,您可以覆盖默认机制,并提供您自己的机制; 这可能适合某些特殊情况。 为此,您可以使用java 中的隐藏功能之一。

重要的是要注意,序列化的是对象的“值”或内容,而不是类定义。 因此方法不是序列化的。

这是一个非常基本的示例,带有注释以方便阅读:

import java.io.*;
import java.util.*;

// This class implements "Serializable" to let the system know
// it's ok to do it. You as programmer are aware of that.
public class SerializationSample implements Serializable {

    // These attributes conform the "value" of the object.

    // These two will be serialized;
    private String aString = "The value of that string";
    private int    someInteger = 0;

    // But this won't since it is marked as transient.
    private transient List<File> unInterestingLongLongList;

    // Main method to test.
    public static void main( String [] args ) throws IOException  { 

        // Create a sample object, that contains the default values.
        SerializationSample instance = new SerializationSample();

        // The "ObjectOutputStream" class has the default 
        // definition to serialize an object.
        ObjectOutputStream oos = new ObjectOutputStream( 
                               // By using "FileOutputStream" we will 
                               // Write it to a File in the file system
                               // It could have been a Socket to another 
                               // machine, a database, an in memory array, etc.
                               new FileOutputStream(new File("o.ser")));

        // do the magic  
        oos.writeObject( instance );
        // close the writing.
        oos.close();
    }
}

当我们运行该程序时,会创建文件“o.ser”,我们可以看到后面发生了什么。

如果我们将 someInteger 的值更改为 Integer.MAX_VALUE,我们可以比较输出以查看差异。

下面的屏幕截图准确地显示了这种差异:

alt text

你能发现差异吗? ;)

Java 序列化中还有一个额外的相关字段:serialversionUID< /a> 但我想这已经太长了,无法涵盖它。

You can think of serialization as the process of converting an object instance into a sequence of bytes (which may be binary or not depending on the implementation).

It is very useful when you want to transmit one object data across the network, for instance from one JVM to another.

In Java, the serialization mechanism is built into the platform, but you need to implement the Serializable interface to make an object serializable.

You can also prevent some data in your object from being serialized by marking the attribute as transient.

Finally you can override the default mechanism, and provide your own; this may be suitable in some special cases. To do this, you use one of the hidden features in java.

It is important to notice that what gets serialized is the "value" of the object, or the contents, and not the class definition. Thus methods are not serialized.

Here is a very basic sample with comments to facilitate its reading:

import java.io.*;
import java.util.*;

// This class implements "Serializable" to let the system know
// it's ok to do it. You as programmer are aware of that.
public class SerializationSample implements Serializable {

    // These attributes conform the "value" of the object.

    // These two will be serialized;
    private String aString = "The value of that string";
    private int    someInteger = 0;

    // But this won't since it is marked as transient.
    private transient List<File> unInterestingLongLongList;

    // Main method to test.
    public static void main( String [] args ) throws IOException  { 

        // Create a sample object, that contains the default values.
        SerializationSample instance = new SerializationSample();

        // The "ObjectOutputStream" class has the default 
        // definition to serialize an object.
        ObjectOutputStream oos = new ObjectOutputStream( 
                               // By using "FileOutputStream" we will 
                               // Write it to a File in the file system
                               // It could have been a Socket to another 
                               // machine, a database, an in memory array, etc.
                               new FileOutputStream(new File("o.ser")));

        // do the magic  
        oos.writeObject( instance );
        // close the writing.
        oos.close();
    }
}

When we run this program, the file "o.ser" is created and we can see what happened behind.

If we change the value of: someInteger to, for example Integer.MAX_VALUE, we may compare the output to see what the difference is.

Here's a screenshot showing precisely that difference:

alt text

Can you spot the differences? ;)

There is an additional relevant field in Java serialization: The serialversionUID but I guess this is already too long to cover it.

┼── 2024-07-18 13:14:50

敢于回答6年前的问题,为刚接触Java的人增加了一个非常高层次的理解

什么是序列化?

将对象转换为字节

什么是反序列化?

将字节转换回对象(反序列化)。

什么时候使用序列化?

当我们想要持久化对象时。
当我们希望对象在 JVM 的生命周期之外继续存在时。

现实世界的例子:

ATM:当账户持有人尝试通过 ATM 从服务器提取资金时,账户持有人信息(如提款详细信息)将被序列化并发送到服务器,在服务器中详细信息将被反序列化并用于执行操作。

java中序列化是如何执行的。

  1. 实现java.io.Serialized接口(标记接口,因此没有方法可以实现)。

  2. 持久化对象:使用java.io.ObjectOutputStream类,它是一个过滤器流,它是较低级别字节流的包装器(将对象写入文件系统或跨网络传输扁平对象)网线并在另一侧重建)。

  • writeObject(<>) - 写入对象
  • readObject() - 读取序列化对象

记住:

当您序列化一个对象时,只会保存该对象的状态,而不是该对象的类文件或方法。

当您序列化 2 字节对象时,您会看到 51 字节序列化文件。

如何序列化和反序列化对象的步骤。

回答:它是如何转换为 51 字节文件的?

  • 首先写入序列化流魔术数据(STREAM_MAGIC=“AC ED”且STREAM_VERSION=JVM 版本)。
  • 然后它写出与实例关联的类的元数据(类的长度、类的名称、serialVersionUID)。
  • 然后它递归地写出超类的元数据,直到找到java.lang.Object
  • 然后从与实例关联的实际数据开始。
  • 最后将与实例关联的对象的数据从元数据开始写入实际内容。

您还可以在此处查看我的Youtube 视频说明

编辑:参考链接阅读。

这将回答一些常见问题:

  1. 如何不序列化类中的任何字段。
    Ans:使用transient关键字

  2. 当子类被序列化时,父类也会被序列化吗?
    答:不,如果父级没有扩展 Serialized 接口的parents 字段,则不会被序列化。

  3. 当父类被序列化时,子类也会被序列化吗?
    Ans:是的,默认情况下子类也会被序列化。

  4. 如何避免子类被序列化?
    答:A. 重写 writeObject 和 readObject 方法并抛出 NotSerializedException

    b. 您也可以在子类中将所有字段标记为瞬态。

  5. 一些系统级类,例如 Thread、OutputStream 及其子类以及 Socket 是不可序列化的。

Daring to answer the 6-year-old question, adding just a very high-level understanding for people new to Java

What is Serialization?

Converting an object to bytes

What is Deserialization?

Converting bytes back to an object (Deserialization).

When is serialization used?

When we want to Persist the Object.
When we want the object to exist beyond the lifetime of the JVM.

Real World Example:

ATM: When the account holder tries to withdraw money from the server through ATM, the account holder information like withdrawal details will be serialized and sent to the server where the details are deserialized and used to perform operations.

How serialization is performed in java.

  1. Implement java.io.Serializable interface (marker interface so no method to implement).

  2. Persist the object: Use java.io.ObjectOutputStream class, a filter stream which is a wrapper around a lower-level byte stream (to write Object to file systems or transfer a flattened object across a network wire and rebuilt on the other side).

  • writeObject(<<instance>>) - to write an object
  • readObject() - to read an serialized Object

Remember:

When you serialize an object, only the object's state will be saved, not the object's class file or methods.

When you serialized a 2-byte object, you see 51 bytes serialized file.

Steps how the object is serialized and de-serialized.

Answer for: How did it convert to 51 bytes file?

  • First writes the serialization stream magic data (STREAM_MAGIC= "AC ED" and STREAM_VERSION=version of the JVM).
  • Then it writes out the metadata of the class associated with an instance (length of the class, the name of the class, serialVersionUID).
  • Then it recursively writes out the metadata of the superclass until it finds java.lang.Object.
  • Then starts with the actual data associated with the instance.
  • Finally writes the data of objects associated with the instance starting from metadata to the actual content.

you can also check my Youtube video explanation here

Edit : Reference link to read.

This will answer a few frequent questions:

  1. How not to serialize any field in the class.
    Ans: use transient keyword

  2. When child class is serialized does parent class get serialized?
    Ans: No, If a parent is not extending the Serializable interface parents field don't get serialized.

  3. When a parent is serialized does child class get serialized?
    Ans: Yes, by default child class also gets serialized.

  4. How to avoid child class from getting serialized?
    Ans: a. Override writeObject and readObject method and throw NotSerializableException.

    b. also you can mark all fields transient in child class.

  5. Some system-level classes such as Thread, OutputStream, and its subclasses, and Socket are not serializable.

风吹短裙飘 2024-07-18 13:14:50

序列化是将内存中的“活动”对象转换为可以存储在某处(例如内存中、磁盘上)的格式,然后“反序列化”回活动对象。

Serialization is taking a "live" object in memory and converting it to a format that can be stored somewhere (eg. in memory, on disk) and later "deserialized" back into a live object.

つ可否回来 2024-07-18 13:14:50

我喜欢@OscarRyz 呈现的方式。 虽然在这里我继续序列化的故事,它最初是由@阿米特古普塔。

尽管了解机器人类结构并拥有序列化数据,地球科学家仍无法反序列化使机器人工作的数据。

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

火星的科学家们正在等待全额付款。 付款完成后,火星科学家与地球科学家共享 serialversionUID。 地球科学家将其设置为机器人级别,一切都变得很好。

I liked the way @OscarRyz presents. Although here i am continuing the story of serialization which was originally written by @amitgupta.

Even though knowing about the robot class structure and having serialized data Earth's scientist were not able to deserialize the data which can make robots working.

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

Mars's scientists were waiting for the complete payment. Once the payment was done Mars's scientists shared the serialversionUID with Earth's scientists. Earth's scientist set it to robot class and everything became fine.

清风不识月 2024-07-18 13:14:50

我自己博客的两分钱:

这里有详细的解释序列化:(我自己的博客)

序列化:

序列化是持久化对象状态的过程。 它以字节序列的形式表示和存储。 这可以存储在文件中。 从文件中读取对象状态并恢复它的过程称为反序列化。

序列化的需求是什么?

在现代架构中,总是需要存储对象状态然后检索它。 例如,在 Hibernate 中,要存储对象,我们应该使类可序列化。 它的作用是,一旦对象状态以字节形式保存,就可以将其传输到另一个系统,然后该系统可以从状态中读取并检索类。 对象状态可以来自数据库或不同的 jvm 或来自单独的组件。 借助序列化,我们可以检索对象状态。

代码示例和说明:

首先让我们看一下Item类:

public class Item implements Serializable{

    /**
    *  This is the Serializable class
    */
    private static final long serialVersionUID = 475918891428093041L;
    private Long itemId;
    private String itemName;
    private transient Double itemCostPrice;
    public Item(Long itemId, String itemName, Double itemCostPrice) {
        super();
        this.itemId = itemId;
        this.itemName = itemName;
        this.itemCostPrice = itemCostPrice;
      }

      public Long getItemId() {
          return itemId;
      }

     @Override
      public String toString() {
          return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
       }


       public void setItemId(Long itemId) {
           this.itemId = itemId;
       }

       public String getItemName() {
           return itemName;
       }
       public void setItemName(String itemName) {
            this.itemName = itemName;
        }

       public Double getItemCostPrice() {
            return itemCostPrice;
        }

        public void setItemCostPrice(Double itemCostPrice) {
             this.itemCostPrice = itemCostPrice;
        }
}

在上面的代码中可以看到Item类实现了Serialized

这是使类能够序列化的接口。

现在我们可以看到一个名为 serialVersionUID 的变量被初始化为 Long 变量。 该数字由编译器根据类的状态和类属性计算得出。 当 jvm 从文件中读取对象状态时,该数字将帮助 jvm 识别对象的状态。

为此我们可以看一下Oracle官方文档:

序列化运行时与每个可序列化类关联
版本号,称为serialVersionUID,在
反序列化以验证序列化的发送者和接收者
对象已加载与该对象兼容的类
尊重序列化。 如果接收者已经加载了一个类
具有与该对象不同的serialVersionUID的对象
相应的发送者的类,那么反序列化将导致
无效类异常。 可序列化的类可以声明自己的
通过声明名为的字段来显式地显示serialVersionUID
“serialVersionUID”必须是静态的、最终的且为 long 类型:
ANY-ACCESS-MODIFIER 静态最终长serialVersionUID = 42L; 如果一个
可序列化类没有显式声明一个serialVersionUID,
那么序列化运行时将计算默认值
该类的serialVersionUID值基于各个方面
类,如 Java(TM) 对象序列化中所述
规格。 不过,强烈建议所有
可序列化类显式声明serialVersionUID值,因为
默认的serialVersionUID计算对类高度敏感
细节可能会因编译器实现而异,并且可以
因此会导致意外的 InvalidClassExceptions
反序列化。 因此,要保证serialVersionUID一致
跨不同java编译器实现的值,可序列化
类必须声明显式的serialVersionUID 值。 也是
强烈建议显式的serialVersionUID声明使用
尽可能使用 private 修饰符,因为此类声明仅适用于
立即声明类 --serialVersionUID 字段不是
作为继承成员很有用。

如果您注意到我们使用了另一个关键字,那就是“transient”。

如果字段不可序列化,则必须将其标记为瞬态。 在这里,我们将 itemCostPrice 标记为瞬态,并且不希望将其写入文件中。

现在让我们看看如何将对象的状态写入文件中,然后从那里读取它。

public class SerializationExample {

    public static void main(String[] args){
        serialize();
       deserialize();
    } 

    public static void serialize(){

         Item item = new Item(1L,"Pen", 12.55);
         System.out.println("Before Serialization" + item);

         FileOutputStream fileOut;
         try {
             fileOut = new FileOutputStream("/tmp/item.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(item);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved in /tmp/item.ser");
           } catch (FileNotFoundException e) {

                  e.printStackTrace();
           } catch (IOException e) {

                  e.printStackTrace();
           }
      }

    public static void deserialize(){
        Item item;

        try {
                FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
                ObjectInputStream in = new ObjectInputStream(fileIn);
                item = (Item) in.readObject();
                System.out.println("Serialized data is read from /tmp/item.ser");
                System.out.println("After Deserialization" + item);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
               e.printStackTrace();
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        }
     }
}

在上面我们可以看到一个对象的序列化和反序列化的例子。

为此我们使用了两个类。 为了序列化对象,我们使用了 ObjectOutputStream。 我们使用 writeObject 方法将对象写入文件中。

对于反序列化,我们使用了 ObjectInputStream,它从文件中读取对象。 它使用 readObject 从文件中读取对象数据。

上述代码的输出如下:

Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]

请注意,反序列化对象中的 itemCostPricenull,因为它未写入。

我们已经在本文第一部分讨论了 Java 序列化的基础知识。

现在让我们深入讨论它及其工作原理。

首先让我们从 serialversionuid 开始。

serialVersionUID 用作 Serialized 类中的版本控制。

如果您没有显式声明serialVersionUID,JVM 将根据 Serialized 类的各种属性自动为您执行此操作。

Java 的计算serialversionuid 的算法(在此处阅读更多详细信息)

  1. 类名。
  2. 以 32 位整数形式编写的类修饰符。
  3. 每个接口的名称按名称排序。
  4. 对于按字段名称排序的类的每个字段(私有静态和私有瞬态字段除外:字段的名称。
    字段的修饰符写为 32 位整数。 描述符
    领域的。
  5. 如果存在类初始值设定项,请写出以下内容:方法的名称。
  6. 方法的修饰符,java.lang.reflect.Modifier.STATIC,写为 32 位整数。
  7. 方法的描述符 ()V。
  8. 对于按方法名称和签名排序的每个非私有构造函数:方法的名称,. 的修饰符
    方法写为 32 位整数。 方法的描述符。
  9. 对于按方法名称和签名排序的每个非私有方法:方法的名称。 该方法的修饰符写为
    32 位整数。 方法的描述符。
  10. SHA-1 算法在 DataOutputStream 生成的字节流上执行,并生成五个 32 位值 sha[0..4]。 这
    哈希值由第一个和第二个 32 位值组合而成
    SHA-1 消息摘要。 如果消息摘要的结果,则五个
    32 位字 H0 H1 H2 H3 H4,位于名为 5 个 int 值的数组中
    sha,哈希值将计算如下:
    long hash = ((sha[0] >>> 24) & 0xFF) |
>            ((sha[0] >>> 16) & 0xFF) << 8 |
>            ((sha[0] >>> 8) & 0xFF) << 16 |
>            ((sha[0] >>> 0) & 0xFF) << 24 |
>            ((sha[1] >>> 24) & 0xFF) << 32 |
>            ((sha[1] >>> 16) & 0xFF) << 40 |
>            ((sha[1] >>> 8) & 0xFF) << 48 |
>        ((sha[1] >>> 0) & 0xFF) << 56;

Java 的序列化算法

序列化对象的算法描述如下:
1. 它写出与实例关联的类的元数据。
2. 它递归地写出超类的描述,直到找到java.lang.object
3. 一旦完成元数据信息的写入,就会开始写入与实例关联的实际数据。 但这一次,它
从最顶层的超类开始。
4. 从最小的超类到最派生的类,递归地写入与实例关联的数据。

要记住的事情:

  1. 类中的静态字段无法序列化。

    公共类 A 实现 Serialized{ 
           字符串 s; 
           static String staticString = "我不会被序列化"; 
      } 
      
  2. 如果读取的类中的serialversionuid不同,则会抛出InvalidClassException异常。

  3. 如果一个类实现了可序列化,那么它的所有子类也将是可序列化的。

    公共类 A 实现 Serialized {....}; 
    
      public class B extends A{...} //也可序列化 
      
  4. 如果一个类引用了另一个类,则所有引用都必须是可序列化的,否则将不会执行序列化过程。 在这种情况下,运行时会抛出NotSerializedException

例如:

public class B{
     String s,
     A a; // class A needs to be serializable i.e. it must implement Serializable
}

My Two cents from my own blog:

Here is a detailed explanation of the Serialization: (my own blog)

Serialization:

Serialization is the process of persisting the state of an object. It is represented and stored in the form of a sequence of bytes. This can be stored in a file. The process to read the state of the object from the file and restoring it is called deserialization.

What is the need of Serialization?

In modern day architecture, there is always a need to store object state and then retrieve it. For example in Hibernate, to store a object we should make the class Serializable. What it does, is that once the object state is saved in the form of bytes it can be transferred to another system which can then read from the state and retrieve the class. The object state can come from a database or a different jvm or from a separate component. With the help of Serialization we can retrieve the Object state.

Code Example and explanation:

First let's have a look at the Item Class:

public class Item implements Serializable{

    /**
    *  This is the Serializable class
    */
    private static final long serialVersionUID = 475918891428093041L;
    private Long itemId;
    private String itemName;
    private transient Double itemCostPrice;
    public Item(Long itemId, String itemName, Double itemCostPrice) {
        super();
        this.itemId = itemId;
        this.itemName = itemName;
        this.itemCostPrice = itemCostPrice;
      }

      public Long getItemId() {
          return itemId;
      }

     @Override
      public String toString() {
          return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
       }


       public void setItemId(Long itemId) {
           this.itemId = itemId;
       }

       public String getItemName() {
           return itemName;
       }
       public void setItemName(String itemName) {
            this.itemName = itemName;
        }

       public Double getItemCostPrice() {
            return itemCostPrice;
        }

        public void setItemCostPrice(Double itemCostPrice) {
             this.itemCostPrice = itemCostPrice;
        }
}

In the above code it can be seen that Item class implements Serializable.

This is the interface that enables a class to be serializable.

Now we can see a variable called serialVersionUID is initialized to Long variable. This number is calculated by the compiler based on the state of the class and the class attributes. This is the number that will help the jvm identify the state of an object when it reads the state of the object from file.

For that we can have a look at the official Oracle Documentation:

The serialization runtime associates with each serializable class a
version number, called a serialVersionUID, which is used during
deserialization to verify that the sender and receiver of a serialized
object have loaded classes for that object that are compatible with
respect to serialization. If the receiver has loaded a class for the
object that has a different serialVersionUID than that of the
corresponding sender's class, then deserialization will result in an
InvalidClassException. A serializable class can declare its own
serialVersionUID explicitly by declaring a field named
"serialVersionUID" that must be static, final, and of type long:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; If a
serializable class does not explicitly declare a serialVersionUID,
then the serialization runtime will calculate a default
serialVersionUID value for that class based on various aspects of the
class, as described in the Java(TM) Object Serialization
Specification. However, it is strongly recommended that all
serializable classes explicitly declare serialVersionUID values, since
the default serialVersionUID computation is highly sensitive to class
details that may vary depending on compiler implementations, and can
thus result in unexpected InvalidClassExceptions during
deserialization. Therefore, to guarantee a consistent serialVersionUID
value across different java compiler implementations, a serializable
class must declare an explicit serialVersionUID value. It is also
strongly advised that explicit serialVersionUID declarations use the
private modifier where possible, since such declarations apply only to
the immediately declaring class--serialVersionUID fields are not
useful as inherited members.

If you have noticed there is another keyword we have used which is transient.

If a field is not serializable, it must be marked transient. Here we marked the itemCostPrice as transient and don't want it to be written in a file

Now let's have a look on how to write the state of an object in the file and then read it from there.

public class SerializationExample {

    public static void main(String[] args){
        serialize();
       deserialize();
    } 

    public static void serialize(){

         Item item = new Item(1L,"Pen", 12.55);
         System.out.println("Before Serialization" + item);

         FileOutputStream fileOut;
         try {
             fileOut = new FileOutputStream("/tmp/item.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(item);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved in /tmp/item.ser");
           } catch (FileNotFoundException e) {

                  e.printStackTrace();
           } catch (IOException e) {

                  e.printStackTrace();
           }
      }

    public static void deserialize(){
        Item item;

        try {
                FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
                ObjectInputStream in = new ObjectInputStream(fileIn);
                item = (Item) in.readObject();
                System.out.println("Serialized data is read from /tmp/item.ser");
                System.out.println("After Deserialization" + item);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
               e.printStackTrace();
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        }
     }
}

In the above we can see an example of serialization and deserialization of an object.

For that we used two classes. For serializing the object we have used ObjectOutputStream. We have used the method writeObject to write the object in the file.

For Deserializing we have used ObjectInputStream which reads from the object from the file. It uses readObject to read the object data from the file.

The output of the above code would be like:

Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]

Notice that itemCostPrice from deserialized object is null as it was not written.

We have already discussed the basics of Java Serialization in part I of this article.

Now let's discuss it deeply and how it works.

First let's start with the serialversionuid.

The serialVersionUID is used as a version control in a Serializable class.

If you do not explicitly declare a serialVersionUID, JVM will do it for you automatically, based on various properties of the Serializable class.

Java's Algorithm of Calculating serialversionuid (Read more details here)

  1. The class name.
    1. The class modifiers written as a 32-bit integer.
    2. The name of each interface sorted by name.
    3. For each field of the class sorted by field name (except private static and private transient fields: The name of the field. The
      modifiers of the field written as a 32-bit integer. The descriptor
      of the field.
    4. If a class initializer exists, write out the following: The name of the method, .
    5. The modifier of the method, java.lang.reflect.Modifier.STATIC, written as a 32-bit integer.
    6. The descriptor of the method, ()V.
    7. For each non-private constructor sorted by method name and signature: The name of the method, . The modifiers of the
      method written as a 32-bit integer. The descriptor of the method.
    8. For each non-private method sorted by method name and signature: The name of the method. The modifiers of the method written as a
      32-bit integer. The descriptor of the method.
    9. The SHA-1 algorithm is executed on the stream of bytes produced by DataOutputStream and produces five 32-bit values sha[0..4]. The
      hash value is assembled from the first and second 32-bit values of the
      SHA-1 message digest. If the result of the message digest, the five
      32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
      sha, the hash value would be computed as follows:
    long hash = ((sha[0] >>> 24) & 0xFF) |
>            ((sha[0] >>> 16) & 0xFF) << 8 |
>            ((sha[0] >>> 8) & 0xFF) << 16 |
>            ((sha[0] >>> 0) & 0xFF) << 24 |
>            ((sha[1] >>> 24) & 0xFF) << 32 |
>            ((sha[1] >>> 16) & 0xFF) << 40 |
>            ((sha[1] >>> 8) & 0xFF) << 48 |
>        ((sha[1] >>> 0) & 0xFF) << 56;

Java's serialization algorithm

The algorithm to serialize an object is described as below:
1. It writes out the metadata of the class associated with an instance.
2. It recursively writes out the description of the superclass until it finds java.lang.object.
3. Once it finishes writing the metadata information, it then starts with the actual data associated with the instance. But this time, it
starts from the topmost superclass.
4. It recursively writes the data associated with the instance, starting from the least superclass to the most-derived class.

Things To Keep In Mind:

  1. Static fields in a class cannot be serialized.

    public class A implements Serializable{
         String s;
         static String staticString = "I won't be serializable";
    }
    
  2. If the serialversionuid is different in the read class it will throw a InvalidClassException exception.

  3. If a class implements serializable then all its sub classes will also be serializable.

    public class A implements Serializable {....};
    
    public class B extends A{...} //also Serializable
    
  4. If a class has a reference of another class, all the references must be Serializable otherwise serialization process will not be performed. In such case, NotSerializableException is thrown at runtime.

Eg:

public class B{
     String s,
     A a; // class A needs to be serializable i.e. it must implement Serializable
}
坐在坟头思考人生 2024-07-18 13:14:50

序列化在java中意味着持久化对象。 如果你想保存对象的状态并想稍后重建状态(可能在另一个JVM中)可以使用序列化。

请注意,只会保存对象的属性。 如果你想再次复活对象,你应该有类文件,因为只会存储成员变量,而不存储成员函数。

例如:

ObjectInputStream oos = new ObjectInputStream(                                 
                                 new FileInputStream(  new File("o.ser")) ) ;
SerializationSample SS = (SearializationSample) oos.readObject();

Searialized 是一个标记接口,它标记您的类是可序列化的。 标记接口意味着它只是一个空接口,使用该接口将通知 JVM 该类可以序列化。

Serialization means persisting objects in java. If you want to save the state of the object and want to rebuild the state later (may be in another JVM) serialization can be used.

Note that the properties of an object is only going to be saved. If you want to resurrect the object again you should have the class file, because the member variables only will be stored and not the member functions.

eg:

ObjectInputStream oos = new ObjectInputStream(                                 
                                 new FileInputStream(  new File("o.ser")) ) ;
SerializationSample SS = (SearializationSample) oos.readObject();

The Searializable is a marker interface which marks that your class is serializable. Marker interface means that it is just an empty interface and using that interface will notify the JVM that this class can be made serializable.

孤独患者 2024-07-18 13:14:50

序列化是将对象的状态转换为位以便将其存储在硬盘驱动器上的过程。 当您反序列化同一对象时,它将稍后保留其状态。 它允许您重新创建对象,而无需手动保存对象的属性。

http://en.wikipedia.org/wiki/Serialization

Serialization is the process of converting an object's state to bits so that it can be stored on a hard drive. When you deserialize the same object, it will retain its state later. It lets you recreate objects without having to save the objects' properties by hand.

http://en.wikipedia.org/wiki/Serialization

小巷里的女流氓 2024-07-18 13:14:50

Java 对象序列化

在此处输入图像描述

序列化是一种将 Java 对象图转换为字节数组以进行存储(到磁盘文件)或传输的机制(跨网络),然后通过使用反序列化,我们可以恢复对象图。
使用引用共享机制正确恢复对象图。 但在存储之前,请检查输入文件/网络中的serialVersionUID和.class文件serialVersionUID是否相同。 如果不是,则抛出 java.io.InvalidClassException

每个版本化的类必须标识它能够写入流并从中读取的原始类版本。 例如,版本化类必须声明:

serialVersionUID 语法

// ANY-ACCESS-MODIFIER static Final long serialVersionUID = (64位有)L; 
  私有静态最终长serialVersionUID = 3487495895819393L; 
  

serialVersionUID 是对于序列化过程至关重要。 但开发人员可以选择将其添加到java源文件中。 如果不包含serialVersionUID,序列化运行时将生成serialVersionUID并将其与类关联。 序列化对象将包含此serialVersionUID 以及其他数据。

注意 - 强烈建议所有可序列化类显式声明一个serialVersionUID,因为默认的serialVersionUID计算对类细节高度敏感,这些细节可能会因编译器实现而异 ,因此可能会导致反序列化过程中出现意外的serialVersionUID冲突,从而导致反序列化失败。

检查可序列化类

在此处输入图像描述


Java 对象只能序列化。 如果一个类或其任何超类实现了java.io.Serialized接口
或其子接口,java.io.Externalizable

  • 类必须实现java.io.Serialized接口才能成功序列化其对象。 Serialized 是一个标记接口,用于通知编译器实现它的类必须添加可序列化行为。 这里 Java 虚拟机 (JVM) 负责其自动序列化。

    <块引用>

    瞬态关键字: java.io.Serialized 接口

    在序列化对象时,如果我们不希望对象的某些数据成员被序列化,我们可以使用瞬态修饰符。 瞬态关键字将阻止该数据成员被序列化。

    • 序列化过程会忽略声明为瞬态或静态的字段。

    <块引用>

    瞬态 & 易挥发

    <前><代码>+--------------+--------+-------------------- ------------------+
    | 旗帜名称 | 价值| 解读|
    +--------------+--------+------------------------ ------------+
    | ACC_VOLATILE | ACC_VOLATILE 0x0040 | 0x0040 声明为易失性; 无法缓存。|
    +--------------+--------+------------------------ ------------+
    |ACC_TRANSIENT | 0x0080 | 0x0080 宣布暂时的; 没有写或|
    | | | 由持久对象管理器读取。|
    +--------------+--------+------------------------ ------------+

    类 Employee 实现可序列化 { 
          私有静态最终长serialVersionUID = 2L; 
          静态 int id; 
    
          内在;  
          字符串名称; 
          临时字符串密码;   // 使用transient关键字意味着它不会被序列化。 
      } 
      
  • 实现Externalized接口允许对象完全控制对象序列化形式的内容和格式。 调用Externalized接口的方法writeExternal和readExternal来保存和恢复对象状态。 当由类实现时,它们可以使用 ObjectOutput 和 ObjectInput 的所有方法写入和读取自己的状态。 对象有责任处理发生的任何版本控制。

    类 Emp 实现了外部化 { 
          内在;  
          字符串名称; 
          临时字符串密码;   // 不使用瞬态,我们需要处理写入和读取。 
    
          @覆盖 
          公共无效writeExternal(ObjectOutput out)抛出IOException { 
              out.writeInt(eno); 
              out.writeUTF(名称); 
              //out.writeUTF(密码); 
          } 
          @覆盖 
          公共无效readExternal(ObjectInput in)抛出IOException,ClassNotFoundException { 
              this.eno = in.readInt(); 
              this.name = in.readUTF(); 
              //this.password = in.readUTF();   // java.io.EOFException 
          } 
      } 
      
  • 只有支持 java.io.Serialized 或 java.io.Externalizable 接口的对象才能写入/流中读取。 每个可序列化对象的类都经过编码,包括类名和类签名、对象字段和数组的值以及从初始对象引用的任何其他对象的闭包。

文件的可序列化示例

public class SerializationDemo {
    static String fileName = "D:/serializable_file.ser";

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        Employee emp = new Employee( );
        Employee.id = 1; // Can not Serialize Class data.
        emp.eno = 77;
        emp.name = "Yash";
        emp.password = "confidential";
        objects_WriteRead(emp, fileName);

        Emp e = new Emp( );
        e.eno = 77;
        e.name = "Yash";
        e.password = "confidential";
        objects_WriteRead_External(e, fileName);

        /*String stubHost = "127.0.0.1";
        Integer anyFreePort = 7777;
        socketRead(anyFreePort); //Thread1
        socketWrite(emp, stubHost, anyFreePort); //Thread2*/

    }
    public static void objects_WriteRead( Employee obj, String serFilename ) throws IOException{
        FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );
        objectOut.writeObject( obj );
        objectOut.close();
        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            FileInputStream fis = new FileInputStream( new File( serFilename ) );
            ObjectInputStream ois = new ObjectInputStream( fis );
            Object readObject;
            readObject = ois.readObject();
            String calssName = readObject.getClass().getName();
            System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException

            Employee emp = (Employee) readObject;
            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void objects_WriteRead_External( Emp obj, String serFilename ) throws IOException {
        FileOutputStream fos = new FileOutputStream(new File( serFilename ));
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );

        obj.writeExternal( objectOut );
        objectOut.flush();

        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            // create a new instance and read the assign the contents from stream.
            Emp emp = new Emp();

            FileInputStream fis = new FileInputStream(new File( serFilename ));
            ObjectInputStream ois = new ObjectInputStream( fis );

            emp.readExternal(ois);

            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

通过网络的可序列化示例

分布式对象 的状态跨越不同的地址空间,或者在同一台计算机上的不同进程中,甚至在通过网络连接的多台计算机中,但它们通过共享数据和调用方法来协同工作。

/**
 * Creates a stream socket and connects it to the specified port number on the named host. 
 */
public static void socketWrite(Employee objectToSend, String stubHost, Integer anyFreePort) {
    try { // CLIENT - Stub[marshalling]
        Socket client = new Socket(stubHost, anyFreePort);
        ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
        out.writeObject(objectToSend);
        out.flush();
        client.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
// Creates a server socket, bound to the specified port. 
public static void socketRead(  Integer anyFreePort ) {
    try { // SERVER - Stub[unmarshalling ]
        ServerSocket serverSocket = new ServerSocket( anyFreePort );
        System.out.println("Server serves on port and waiting for a client to communicate");
            /*System.in.read();
            System.in.read();*/

        Socket socket = serverSocket.accept();
        System.out.println("Client request to communicate on port server accepts it.");

        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        Employee objectReceived = (Employee) in.readObject();
        System.out.println("Server Obj : "+ objectReceived.name );

        socket.close();
        serverSocket.close();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}

@see

Java Object Serialization

enter image description here

Serialization is a mechanism to transform a graph of Java objects into an array of bytes for storage(to disk file) or transmission(across a network), then by using deserialization we can restore the graph of objects.
Graphs of objects are restored correctly using a reference sharing mechanism. But before storing, check whether serialVersionUID from input-file/network and .class file serialVersionUID are the same. If not, throw a java.io.InvalidClassException.

Each versioned class must identify the original class version for which it is capable of writing streams and from which it can read. For example, a versioned class must declare:

serialVersionUID Syntax

// ANY-ACCESS-MODIFIER static final long serialVersionUID = (64-bit has)L;
private static final long serialVersionUID = 3487495895819393L;

serialVersionUID is essential to the serialization process. But it is optional for the developer to add it into the java source file. If a serialVersionUID is not included, the serialization runtime will generate a serialVersionUID and associate it with the class. The serialized object will contain this serialVersionUID along with other data.

Note - It is strongly recommended that all serializable classes explicitly declare a serialVersionUID, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected serialVersionUID conflicts during deserialization, causing deserialization to fail.

Inspecting Serializable Classes

enter image description here


A Java object is only serializable. if a class or any of its superclasses implements either the java.io.Serializable interface
or its subinterface, java.io.Externalizable.

  • A class must implement java.io.Serializable interface in order to serialize its object successfully. Serializable is a marker interface and used to inform the compiler that the class implementing it has to be added serializable behavior. Here Java Virtual Machine (JVM) is responsible for its automatic serialization.

    transient Keyword: java.io.Serializable interface

    While serializing an object, if we don't want certain data members of the object to be serialized we can use the transient modifier. The transient keyword will prevent that data member from being serialized.

    • Fields declared as transient or static are ignored by the serialization process.

    TRANSIENT & VOLATILE

    +--------------+--------+-------------------------------------+
    |  Flag Name   |  Value | Interpretation                      |
    +--------------+--------+-------------------------------------+
    | ACC_VOLATILE | 0x0040 | Declared volatile; cannot be cached.|
    +--------------+--------+-------------------------------------+
    |ACC_TRANSIENT | 0x0080 | Declared transient; not written or  |
    |              |        | read by a persistent object manager.|
    +--------------+--------+-------------------------------------+
    
    class Employee implements Serializable {
        private static final long serialVersionUID = 2L;
        static int id;
    
        int eno; 
        String name;
        transient String password; // Using transient keyword means its not going to be Serialized.
    }
    
  • Implementing the Externalizable interface allows the object to assume complete control over the contents and format of the object's serialized form. The methods of the Externalizable interface, writeExternal and readExternal, are called to save and restore the objects state. When implemented by a class they can write and read their own state using all of the methods of ObjectOutput and ObjectInput. It is the responsibility of the objects to handle any versioning that occurs.

    class Emp implements Externalizable {
        int eno; 
        String name;
        transient String password; // No use of transient, we need to take care of write and read.
    
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeInt(eno);
            out.writeUTF(name);
            //out.writeUTF(password);
        }
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            this.eno = in.readInt();
            this.name = in.readUTF();
            //this.password = in.readUTF(); // java.io.EOFException
        }
    }
    
  • Only objects that support the java.io.Serializable or java.io.Externalizable interface can be written to/read from streams. The class of each serializable object is encoded including the class name and signature of the class, the values of the object's fields and arrays, and the closure of any other objects referenced from the initial objects.

Serializable Example For Files

public class SerializationDemo {
    static String fileName = "D:/serializable_file.ser";

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        Employee emp = new Employee( );
        Employee.id = 1; // Can not Serialize Class data.
        emp.eno = 77;
        emp.name = "Yash";
        emp.password = "confidential";
        objects_WriteRead(emp, fileName);

        Emp e = new Emp( );
        e.eno = 77;
        e.name = "Yash";
        e.password = "confidential";
        objects_WriteRead_External(e, fileName);

        /*String stubHost = "127.0.0.1";
        Integer anyFreePort = 7777;
        socketRead(anyFreePort); //Thread1
        socketWrite(emp, stubHost, anyFreePort); //Thread2*/

    }
    public static void objects_WriteRead( Employee obj, String serFilename ) throws IOException{
        FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );
        objectOut.writeObject( obj );
        objectOut.close();
        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            FileInputStream fis = new FileInputStream( new File( serFilename ) );
            ObjectInputStream ois = new ObjectInputStream( fis );
            Object readObject;
            readObject = ois.readObject();
            String calssName = readObject.getClass().getName();
            System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException

            Employee emp = (Employee) readObject;
            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void objects_WriteRead_External( Emp obj, String serFilename ) throws IOException {
        FileOutputStream fos = new FileOutputStream(new File( serFilename ));
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );

        obj.writeExternal( objectOut );
        objectOut.flush();

        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            // create a new instance and read the assign the contents from stream.
            Emp emp = new Emp();

            FileInputStream fis = new FileInputStream(new File( serFilename ));
            ObjectInputStream ois = new ObjectInputStream( fis );

            emp.readExternal(ois);

            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Serializable Example Over Network

Distributing object's state across different address spaces, either in different processes on the same computer, or even in multiple computers connected via a network, but which work together by sharing data and invoking methods.

/**
 * Creates a stream socket and connects it to the specified port number on the named host. 
 */
public static void socketWrite(Employee objectToSend, String stubHost, Integer anyFreePort) {
    try { // CLIENT - Stub[marshalling]
        Socket client = new Socket(stubHost, anyFreePort);
        ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
        out.writeObject(objectToSend);
        out.flush();
        client.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
// Creates a server socket, bound to the specified port. 
public static void socketRead(  Integer anyFreePort ) {
    try { // SERVER - Stub[unmarshalling ]
        ServerSocket serverSocket = new ServerSocket( anyFreePort );
        System.out.println("Server serves on port and waiting for a client to communicate");
            /*System.in.read();
            System.in.read();*/

        Socket socket = serverSocket.accept();
        System.out.println("Client request to communicate on port server accepts it.");

        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        Employee objectReceived = (Employee) in.readObject();
        System.out.println("Server Obj : "+ objectReceived.name );

        socket.close();
        serverSocket.close();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}

@see

活雷疯 2024-07-18 13:14:50

序列化是将对象保存在存储介质(例如文件或内存缓冲区)中或以二进制形式通过网络连接传输的过程。 序列化的对象与 JVM 无关,并且可以由任何 JVM 重新序列化。 在这种情况下,“内存中”java 对象状态被转换为字节流。 用户无法理解这种类型的文件。 它是一种特殊类型的对象,即由 JVM(Java 虚拟机)重用。 序列化对象的过程也称为压缩或编组对象。

要序列化的对象必须实现 java.io.Serialized 接口。
对象的默认序列化机制写入对象的类、类签名以及所有非瞬态和非静态字段的值。

class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,

ObjectOutput 接口扩展了 DataOutput 接口,并添加了用于序列化对象和将字节写入文件的方法。 ObjectOutputStream 扩展了 java.io.OutputStream 并实现了 ObjectOutput 接口。 它将对象、数组和其他值序列化到流中。 因此,ObjectOutputStream 的构造函数写为:

ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));

上面的代码用于使用 ObjectOutputStream( ) 构造函数创建 ObjectOutput 类的实例,其中将 FileOuputStream 的实例作为参数。

ObjectOutput 接口通过实现ObjectOutputStream 类来使用。 ObjectOutputStream 被构造来序列化对象。

在java中反序列化一个对象

序列化的相反操作称为反序列化,即从一系列字节中提取数据称为反序列化,也称为膨胀或反编组。

ObjectInputStream 扩展了 java.io.InputStream 并实现了 ObjectInput 接口。 它从输入流中反序列化对象、数组和其他值。 因此,ObjectInputStream 的构造函数写为:

ObjectInputStream obj = new ObjectInputStream(new FileInputStream(f));

上面的程序代码创建了 ObjectInputStream 类的实例,以反序列化由 ObjectInputStream< 序列化的文件。 /代码> 类。 上面的代码使用 FileInputStream 类的实例创建实例,该类保存必须反序列化的指定文件对象,因为 ObjectInputStream() 构造函数需要输入流。

Serialization is the process of saving an object in a storage medium (such as a file, or a memory buffer) or to transmit it over a network connection in binary form. The serialized objects are JVM independent and can be re-serialized by any JVM. In this case the "in memory" java objects state are converted into a byte stream. This type of the file can not be understood by the user. It is a special types of object i.e. reused by the JVM (Java Virtual Machine). This process of serializing an object is also called deflating or marshalling an object.

The object to be serialized must implement java.io.Serializable Interface.
Default serialization mechanism for an object writes the class of the object, the class signature, and the values of all non-transient and non-static fields.

class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,

ObjectOutput interface extends the DataOutput interface and adds methods for serializing objects and writing bytes to the file. The ObjectOutputStream extends java.io.OutputStream and implements ObjectOutput interface. It serializes objects, arrays, and other values to a stream. Thus the constructor of ObjectOutputStream is written as:

ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));

Above code has been used to create the instance of the ObjectOutput class with the ObjectOutputStream( ) constructor which takes the instance of the FileOuputStream as a parameter.

The ObjectOutput interface is used by implementing the ObjectOutputStream class. The ObjectOutputStream is constructed to serialize the object.

Deserializing an Object in java

The opposite operation of the serialization is called deserialization i.e. to extract the data from a series of bytes is s known as deserialization which is also called inflating or unmarshalling.

ObjectInputStream extends java.io.InputStream and implements ObjectInput interface. It deserializes objects, arrays, and other values from an input stream. Thus the constructor of ObjectInputStream is written as:

ObjectInputStream obj = new ObjectInputStream(new FileInputStream(f));

Above code of the program creates the instance of the ObjectInputStream class to deserialize that file which had been serialized by the ObjectInputStream class. The above code creates the instance using the instance of the FileInputStream class which holds the specified file object which has to be deserialized because the ObjectInputStream() constructor needs the input stream.

像极了他 2024-07-18 13:14:50

序列化是将 Java 对象转换为字节数组,然后再次转换回对象并保留其保留状态的过程。 对于各种事情很有用,例如通过网络发送对象或将内容缓存到磁盘。

阅读这篇简短的文章了解更多内容,该文章很好地解释了该过程的编程部分然后移至 Serializable javadoc。 您可能还有兴趣阅读 此相关问题

Serialization is the process of turning a Java object into byte array and then back into object again with its preserved state. Useful for various things like sending objects over network or caching things to disk.

Read more from this short article which explains programming part of the process quite well and then move over to to Serializable javadoc. You may also be interested in reading this related question.

旧人 2024-07-18 13:14:50

将文件作为对象返回: http://www.tutorialspoint.com/java/java_serialization.htm

        import java.io.*;

        public class SerializeDemo
        {
           public static void main(String [] args)
           {
              Employee e = new Employee();
              e.name = "Reyan Ali";
              e.address = "Phokka Kuan, Ambehta Peer";
              e.SSN = 11122333;
              e.number = 101;

              try
              {
                 FileOutputStream fileOut =
                 new FileOutputStream("/tmp/employee.ser");
                 ObjectOutputStream out = new ObjectOutputStream(fileOut);
                 out.writeObject(e);
                 out.close();
                 fileOut.close();
                 System.out.printf("Serialized data is saved in /tmp/employee.ser");
              }catch(IOException i)
              {
                  i.printStackTrace();
              }
           }
        }

    import java.io.*;
    public class DeserializeDemo
    {
       public static void main(String [] args)
       {
          Employee e = null;
          try
          {
             FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             e = (Employee) in.readObject();
             in.close();
             fileIn.close();
          }catch(IOException i)
          {
             i.printStackTrace();
             return;
          }catch(ClassNotFoundException c)
          {
             System.out.println("Employee class not found");
             c.printStackTrace();
             return;
          }
          System.out.println("Deserialized Employee...");
          System.out.println("Name: " + e.name);
          System.out.println("Address: " + e.address);
          System.out.println("SSN: " + e.SSN);
          System.out.println("Number: " + e.number);
        }
    }

Return the file as an Object : http://www.tutorialspoint.com/java/java_serialization.htm

        import java.io.*;

        public class SerializeDemo
        {
           public static void main(String [] args)
           {
              Employee e = new Employee();
              e.name = "Reyan Ali";
              e.address = "Phokka Kuan, Ambehta Peer";
              e.SSN = 11122333;
              e.number = 101;

              try
              {
                 FileOutputStream fileOut =
                 new FileOutputStream("/tmp/employee.ser");
                 ObjectOutputStream out = new ObjectOutputStream(fileOut);
                 out.writeObject(e);
                 out.close();
                 fileOut.close();
                 System.out.printf("Serialized data is saved in /tmp/employee.ser");
              }catch(IOException i)
              {
                  i.printStackTrace();
              }
           }
        }

    import java.io.*;
    public class DeserializeDemo
    {
       public static void main(String [] args)
       {
          Employee e = null;
          try
          {
             FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             e = (Employee) in.readObject();
             in.close();
             fileIn.close();
          }catch(IOException i)
          {
             i.printStackTrace();
             return;
          }catch(ClassNotFoundException c)
          {
             System.out.println("Employee class not found");
             c.printStackTrace();
             return;
          }
          System.out.println("Deserialized Employee...");
          System.out.println("Name: " + e.name);
          System.out.println("Address: " + e.address);
          System.out.println("SSN: " + e.SSN);
          System.out.println("Number: " + e.number);
        }
    }
白芷 2024-07-18 13:14:50

|*| 序列化类:将对象转换为字节,然后将字节转换回对象(反序列化)。

class NamCls implements Serializable
{
    int NumVar;
    String NamVar;
}

|=> 对象序列化是将对象的状态转换为字节流的过程。

  • |-> 当您希望对象在 JVM 的生命周期之外存在时实现。
  • |-> 序列化对象可以存储在数据库中。
  • |-> 可序列化对象无法被人类读取和理解,因此我们可以实现安全性。

|=> 对象反序列化是获取对象状态并将其存储到对象(java.lang.Object)中的过程。

  • |-> 在存储其状态之前,它会检查输入文件/网络中的serialVersionUID和.class文件serialVersionUID是否相同。
      如果没有抛出java.io.InvalidClassException。

|=> 仅当 Java 对象的类或其任何超类

  • 实现 java.io.Serializable 接口或其
  • 子接口 java.io.Externalizable 时,该对象才可序列化。

|=> 类中的静态字段无法序列化。

class NamCls implements Serializable
{
    int NumVar;
    static String NamVar = "I won't be serializable";;
}

|=> 如果您不想序列化类的变量,请使用瞬态关键字

class NamCls implements Serializable
{
    int NumVar;
    transient String NamVar;
}

|=> 如果一个类实现了可序列化,那么它的所有子类也将是可序列化的。

|=> 如果一个类引用了另一个类,则所有引用都必须是可序列化的,否则将不会执行序列化过程。 在这种情况下,
运行时会抛出NotSerializedException。

|*| Serializing a class : Converting an object to bytes and bytes back to object (Deserialization).

class NamCls implements Serializable
{
    int NumVar;
    String NamVar;
}

|=> Object-Serialization is process of converting the state of an object into steam of bytes.

  • |-> Implement when you want the object to exist beyond the lifetime of the JVM.
  • |-> Serialized Object can be stored in Database.
  • |-> Serializable-objects cannot be read and understood by humans so we can acheive security.

|=> Object-Deserialization is the process of getting the state of an object and store it into an object(java.lang.Object).

  • |-> Before storing its state it checks whether serialVersionUID form input-file/network and .class file serialVersionUID are same.
      If not throw java.io.InvalidClassException.

|=> A Java object is only serializable, if its class or any of its superclasses

  • implements either the java.io.Serializable interface or
  • its subinterface, java.io.Externalizable.

|=> Static fields in a class cannot be serialized.

class NamCls implements Serializable
{
    int NumVar;
    static String NamVar = "I won't be serializable";;
}

|=> If you do not want to serialise a variable of a class use transient keyword

class NamCls implements Serializable
{
    int NumVar;
    transient String NamVar;
}

|=> If a class implements serializable then all its sub classes will also be serializable.

|=> If a class has a reference of another class, all the references must be Serializable otherwise serialization process will not be performed. In such case,
NotSerializableException is thrown at runtime.

追风人 2024-07-18 13:14:48

序列化是将对象转换为一系列字节,以便可以轻松地将对象保存到持久存储或通过通信链路进行流式传输。 然后可以将字节流反序列化 - 转换为原始对象的副本。

Serialization is the conversion of an object to a series of bytes, so that the object can be easily saved to persistent storage or streamed across a communication link. The byte stream can then be deserialized - converted into a replica of the original object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文