什么是对象序列化?

“对象序列化”是什么意思?你能举例解释一下吗?

321117 次浏览

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

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

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

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

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

这篇简短的文章很好地解释了编程过程的一部分阅读更多内容,然后转到可序列化的javadoc。你可能也有兴趣阅读这个相关的问题

您可以将序列化看作是将对象实例转换为字节序列的过程(根据实现的不同,字节序列可能是二进制的,也可能不是)。

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

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

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

最后,您可以覆盖默认机制,并提供您自己的;这可能适用于某些特殊情况。要做到这一点,你需要使用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的值更改为,例如整数。MAX_VALUE,我们可以比较输出,看看有什么不同。

下面的截图正好显示了这种差异:

alt text

你能看出区别吗?;) < /订阅>

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

序列化意味着在java中持久化对象。如果您希望保存对象的状态,并希望稍后重新构建该状态(可能在另一个JVM中),则可以使用序列化。

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

例如:

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

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

我喜欢@OscarRyz的礼物方式。虽然在这里我继续序列化的故事最初是由@amitgupta写的。

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

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

火星的科学家们正在等待全额付款。一旦付款完成,火星的科学家与地球的科学家分享serialversionUID。地球科学家把它设置成机器人级别,一切都好了。

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

要序列化的对象必须实现java.io.Serializable Interface。 对象的默认序列化机制写入对象的类、类签名以及所有非瞬态和非静态字段的值
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()构造函数需要输入流。

Java 对象序列化 . Java enter image description here

Serialization是一种将Java对象图转换为用于存储(to disk file)或传输(across a network)的字节数组的机制,然后通过使用反序列化我们可以恢复对象图。 使用引用共享机制正确地恢复对象的图。但是在存储之前,请检查input-file/network中的serialVersionUID和.class文件中的serialVersionUID是否相同。如果不是,则抛出java.io.InvalidClassException < / p >

每个版本化的类必须确定它能够为其写入流和从中读取流的原始类版本。例如,一个有版本控制的类必须声明:

serialVersionUID的语法

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

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

请注意——强烈建议所有可序列化类显式声明一个serialVersionUID, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations,这样会在反序列化期间导致意外的serialVersionUID冲突,导致反序列化失败。

检查可序列化类

enter image description here


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

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

    瞬态的关键字: java.io.Serializable interface

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

    • 声明为瞬态或静态的字段将被序列化进程忽略。

    瞬态,挥发性

    +--------------+--------+-------------------------------------+
    |  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.
    }
    
  • 实现Externalizable接口允许对象承担对对象序列化形式的内容和格式的完全控制。Externalizable接口的方法writeExternal和readeexternal被调用来保存和恢复对象状态。当由类实现时,它们可以使用ObjectOutput和ObjectInput的所有方法写入和读取自己的状态。对象负责处理发生的任何版本控制。

    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
    }
    }
    
  • 只有支持java.io.Serializable或java.io.Externalizable接口的对象才能是written to/read from流。每个可序列化对象的类都被编码,包括类名和类的签名、对象的字段和数组的值,以及从初始对象引用的任何其他对象的闭包。

文件的序列化示例

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

敢于回答这个6年前的问题,为Java新手增加了非常高级的理解

什么是序列化?

将对象转换为字节

什么是反序列化?

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

什么时候使用序列化?

当我们想持久化对象时。 当我们希望对象在JVM生命周期之后仍然存在时

现实世界的例子:

ATM:当账户持有人试图通过ATM从服务器取款时,提现明细等账户持有人信息将被序列化并发送到服务器,服务器将这些明细反序列化并用于操作。

在java中如何执行序列化。

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

  2. 持久化对象:使用java.io.ObjectOutputStream类,这是一个过滤器流,它是底层字节流的包装器(将object写入文件系统或通过网络传输扁平对象并在另一端重新构建)。

  • writeObject(<<instance>>) -写一个对象
  • readObject() -读取一个序列化的对象

记住:

序列化对象时,只保存对象的状态,不保存对象的类文件或方法。

当你序列化一个2字节的对象时,你会看到51字节的序列化文件。

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

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

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

你也可以检查我的Youtube视频解释

编辑:引用链接来读取。

这将回答一些常见的问题:

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

  2. 当子类被序列化时父类被序列化吗?< br > 答:不,如果父字段没有扩展Serializable接口,父字段就不会被序列化

  3. 当父类被序列化时子类被序列化吗?< br > 答:是的,默认情况下子类也被序列化

  4. 如何避免子类被序列化?< br > 答:a.重写writeObject和readObject方法并抛出NotSerializableException.

    B.你也可以在子类中标记所有暂态字段。

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

将文件作为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);
}
}

我在自己的博客上说:

下面是关于序列化的详细说明:(我自己的博客)

序列化:

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

序列化的需求是什么?

在现代体系结构中,总是需要存储对象状态,然后再检索它。例如,在Hibernate中,要存储一个对象,我们应该使类Serializable。它所做的是,一旦对象状态以字节的形式保存,它就可以传输到另一个系统,然后该系统可以从状态中读取并检索类。对象状态可以来自数据库、不同的jvm或单独的组件。在Serialization的帮助下,我们可以检索对象状态。

代码示例及说明:

首先让我们来看看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;
}
}

在上面的代码中,可以看到类实现了可序列化的

这是使类可序列化的接口。

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

为此,我们可以看看官方的Oracle文档:

序列化运行时与每个可序列化类a相关联 版本号,称为serialVersionUID,在 反序列化验证发送方和接收方是否序列化 对象为该对象加载了与之兼容的类 关于序列化。类的类 对象的serialVersionUID与 对应的发送方类,则反序列化将导致 InvalidClassException。可序列化类可以声明自己的类 serialVersionUID通过声明一个名为 "serialVersionUID"必须是静态的,final的,long类型: ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;如果一个 serializable类没有显式声明serialVersionUID, 然后序列化运行时将计算一个默认值 类的各个方面的serialVersionUID值 类,如Java(TM)对象序列化中所述 规范。然而,强烈建议所有 可序列化类显式声明serialVersionUID值,因为 默认的serialVersionUID计算对类非常敏感 细节可能因编译器实现而异 从而导致意外的invalidclassexception 反序列化。因此,为了保证一致的serialVersionUID 值跨不同的Java编译器实现,一个可序列化的 类必须声明显式的serialVersionUID值。它也是 强烈建议显式的serialVersionUID声明使用 私有修饰符,因为这样的声明只适用于 立即声明类——serialVersionUID字段则不是

如果你注意到,我们使用的另一个关键字是瞬态

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

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

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]

注意,来自反序列化对象的itemCostPrice,因为它没有被写入。

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

现在让我们深入讨论它以及它是如何工作的。

首先让我们从serialversionuid。开始

serialVersionUID在Serializable类中用作版本控制。

如果您没有显式地声明serialVersionUID, JVM将根据Serializable类的各种属性自动为您声明。

Java的计算serialversionuid的算法(在这里阅读更多细节)

  1. 类名。
    1. 类修饰符写为32位整数。
    2. 按名称排序的每个接口的名称。
    3. 对于按字段名排序的类的每个字段(私有静态和私有瞬态字段除外):字段名。的 写为32位整数的字段的修饰符。描述符 这个领域。李< / >
    4. 如果存在类初始化式,则写出以下内容:方法的名称,。
    5. 方法的修饰符:java.lang.reflect.Modifier。STATIC,写为32位整数。
    6. 方法的描述符()V。
    7. 对于每个按方法名和签名排序的非私有构造函数:方法名,。的修饰符 方法编写为32位整数。方法的描述符。李< / >
    8. 对于每个按方法名和签名排序的非私有方法:方法名。方法的修饰符写为 32位整数。
    9. 方法的描述符
    10. sha -1算法在DataOutputStream产生的字节流上执行,生成5个32位的值sha[0..4]。的 对象的第一个和第二个32位值组合成哈希值 SHA-1消息摘要。如果结果是消息摘要,则为五 32位的单词H0 H1 H2 H3 H4,是一个由五个int值命名的数组 Sha,哈希值计算如下:
    11. 李< / ol > < / >
    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. 类中的静态字段不能序列化。

    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
}

|*|序列化一个类:将一个对象转换为字节和字节返回到对象(反序列化)

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

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

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

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

    在存储它的状态之前,它检查input-file/network中的serialVersionUID和.class文件中的serialVersionUID是否相同 如果没有抛出java.io.InvalidClassException.
    . nbspIf not throw java.io.InvalidClassException.
    . nbspIf not throw

只有当Java对象的类或其任何超类
时,该对象才可序列化

  • 实现java.io.Serializable接口或
  • 它的子接口java.io.Externalizable.

|=>类中的静态字段不能序列化

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

|=>如果你不想序列化一个类的变量,使用transient关键字

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

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

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

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

我想象< em >对象序列化/反序列化< / em >在试图移动一个物体通过雨水沟的上下文中。对象本质上被“分解”或序列化分解为自身的更模块化的版本——在本例中是字节序列——以便有效地通过介质。在计算的意义上,我们可以将字节通过排水沟的路径视为类似于字节通过网络的路径。我们正在改变我们的对象,以符合更理想的运输方式或格式。序列化的对象通常存储在二进制文件中,以后可以对该文件进行读、写或同时进行读、写。

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

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

在Java中,使用Serialization和Externalisation接口也可以实现同样的功能