看了一篇简单介绍serialVersionUID的文章,在这里结合javaAPI文档和自己的理解说一下Serializable和serialVersionUID。
一、Serializable
在JavaAPI中已经将这个问题说的很明白了,下面只是简单的概括一下。
1、Serializable是一个标志性接口,没有任何成员变量和方法。需要序列化一个类时只需要声明实现这个接口即可。
2、如果类A中组合了类B的对象的化,序列化类A对象的同时会序列化类B对象,前提是类A和类B都实现了Serializable接口。
3、如果类B继承类A,那么序列化类B分为下面两中情况:
(1)类A没有实现Serializable接口,而类B实现了。那么根据JavaAPI中的说明,如果需要序列化类B,需要保证类A和类B都有无参的构造方法,如果无法默认构造,则必须显式声明。没有无参构造方法的话,在运行时会报异常。
用这种方式试了一下,虽然可以序列化类A继承来的属性(public、protected、包访问),但是不能正确读取,读出来是null,类B自身特有的属性没问题。有待进一步验证。
(2)类A实现了Serializable接口(类B实不实现无所谓,因为继承类A)。通过类B给继承于类A的变量和自身特有的变量赋值,并进行序列化。序列化成功,并可以正确读取。
二、serialVersionUID
serialVersionUID用于可序列化类的版本控制。如果不显式的声明一个serialVersionUID,JVM会基于这个序列化类的不同方面特征自动生成一个。
具体的可以参见JavaAPI文档的Serializable接口说明。
下面用一个例子来说明serialVersionUID的版本控制作用。
下面的类实现了Serializable接口,并且自定义了serialVersionUID=1L
public class Address implements Serializable{
private static final long serialVersionUID = 1L;
String street;
String country;
public void setStreet(String street){
this.street = street;
}
public void setCountry(String country){
this.country = country;
}
public String getStreet(){
return this.street;
}
public String getCountry(){
return this.country;
}
@Override
public String toString() {
return new StringBuffer(" Street : ")
.append(this.street)
.append(" Country : ")
.append(this.country).toString();
}
}
WriteObject类将Address类的对象写入磁盘文件address.ser。
public class WriteObject{
public static void main (String args[]) {
Address address = new Address();
address.setStreet("wall street");
address.setCountry("united state");
try{
FileOutputStream fout = new FileOutputStream("c:\\address.ser");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(address);
oos.close();
System.out.println("Done");
}catch(Exception ex){
ex.printStackTrace();
}
}
}
ReadObject类读取保存了Address对象的文件address.ser
public class ReadObject{
public static void main (String args[]) {
Address address;
try{
FileInputStream fin = new FileInputStream("c:\\address.ser");
ObjectInputStream ois = new ObjectInputStream(fin);
address = (Address) ois.readObject();
ois.close();
System.out.println(address);
}catch(Exception ex){
ex.printStackTrace();
}
}
}
测试类
public class SerialSample {
public static void main(String[] args) {
WriteObject wo=new WriteObject();
ReadObject ro=new ReadObject();
wo.write();
ro.read();
}
}
运行测试类,控制台的显示可以知道对象被序列化存入磁盘文件并正确的读出。下面在Address类中修改serialVersionUID=2L。注释掉测试类中wo.write()这一句并再次执行。控制台出现下面的错误:
java.io.InvalidClassException: *.*.*.Address; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
这是因为序列化的时候serialVersionUID=1L,修改之后我们把一个serialVersionUID=2L的声明引用指向了反序列化后的serialVersionUID=1L的对象。JVM发现了不匹配,所以报错。
这也说明了serialVersionUID在序列化和反序列化的过程中必须匹配。
缺省serialVersionUID。
如果不显式的指定一个serialVersionUID,JVM会根据自有的算法来生成一个缺省的serialVersionUID。
这个缺省的serialVersionUID的计算对类的细节高度敏感,并且会因为不同的JVM而发生变化。在不同的JVM之间进行反序列化会导致InvalidClassExceptions异常。
分享到:
相关推荐
Java 中的 serialVersionUID 是一个非常重要的概念,在实现 Serializable 接口的类中,它扮演着至关重要的角色。那么,serialVersionUID到底是什么?它又是如何生成的?在本篇文章中,我们将详细地解释 ...
在安装 GenerateSerialVersionUID 插件后,可以在 Inspections 设置页面中勾选 Serializable class without 'serialVersionUID',并且还可以在 Severity 中设置提示级别,如 Warning、Error 等,默认为 Warning。...
例如,`MySerializable.java`和`Product.java`两个文件可能分别代表实现了`Serializable`接口的类。`MySerializable`可能是自定义的一个示例类,而`Product`可能是表示产品的类,它们都包含了可序列化的属性。 在`...
当实现 `java.io.Serializable` 接口的类未明确声明 `serialVersionUID` 时,Java 序列化机制将根据编译后的 Class 文件自动生成一个 `serialVersionUID`。此规则下,即使多次重新编译,只要 Class 文件内容不变...
// getters and setters... } ``` 序列化和反序列化的操作通常使用`ObjectOutputStream`和`ObjectInputStream`来完成: ```java // 序列化 try (FileOutputStream fos = new FileOutputStream("object.ser"); ...
// getters and setters } ``` 现在,如果我们有一个`MySerializableClass`的实例`obj`,并希望将其转化为字节数组(即字节流),我们可以使用`ByteArrayOutputStream`和`ObjectOutputStream`。这是基本步骤: ``...
在Java编程语言中,`Serializable`接口是一个非常重要的概念,它是实现对象持久化的关键。本文将深入探讨`Serializable`接口的细节,以及与其相关的高级知识。 `Serializable`接口是Java中的一个标记接口,没有包含...
本教程将详细讲解如何通过Serializable接口来实现Intent对象的传递。 首先,了解Serializable接口。在Java中,Serializable是用于序列化和反序列化的接口。当一个类实现了这个接口,它的实例就可以被转化为一串字节...
在Java编程中,`serialVersionUID` 是一个非常重要的概念,特别是在序列化和反序列化过程中。这个特殊标识符主要用于版本控制,确保不同版本的类在序列化和反序列化时能够正确匹配。当我们讨论`serialVersionUID`时...
在实现Serializable接口时,需要注意的是必须提供一个固定的serialVersionUID变量,这个变量用于标识该类的版本号,以便在反序列化时可以正确地还原对象。例如,在上面的例子中,我们定义了一个User类,并实现了...
Serializable的增删改查操作,已经经过验证,可以直接运行。
java->serializable深入了解 java->serializable深入了解 java->serializable深入了解
在Laravel框架中,"serializable-values"是一个关键概念,它涉及到对象的序列化与反序列化,这对于数据存储和传输至关重要。在这个话题下,我们将深入探讨Laravel如何处理可序列化的值,以及如何利用Luminark提供的...
### C#中Serializable的作用与对象序列化详解 #### 一、引言 在现代软件开发中,特别是基于.NET框架的应用程序开发中,对象序列化是一项非常重要的技术。它允许将对象的状态转换为一种持久的形式(如文件或网络传输...
《深入理解Java序列化:serialVersionUID与序列化过程解析》 在Java编程中,序列化是一种将对象的状态转换为字节流的过程,以便可以存储在磁盘上或在网络上传输。这一过程对于实现持久化、跨网络通信以及分布式计算...
本文将深入探讨两种主要的序列化方式:Serializable和Parcelable,并比较它们的优缺点以及适用场景。 首先,我们来了解什么是序列化。序列化是将对象的状态转换为可存储或可传输的形式的过程。在Android中,这个...
本篇将详细介绍如何通过`Bundle` 传递基本数据类型、Parcelable类型数据以及Serializable类型数据。 ### 一、基本数据类型的传递 在Android中,基本数据类型包括int、boolean、float、double、char等。通过`put()`...
// getters and setters } ``` 4. **序列化过程**:使用`ObjectOutputStream`的`writeObject()`方法将对象写入流,如下所示: ```java MyObject obj = new MyObject(); try (ObjectOutputStream oos = new ...
在实现 Serializable 接口的类中,如果没有显示地定义 serialVersionUID,Java 序列化机制会根据编译的 Class 自动生成一个 serialVersionUID 作序列化版本比较用。 在实际应用中,serialVersionUID 的应用场景非常...
3. 版本兼容性:当类结构发生变化时(如添加、删除或修改字段),需要考虑序列化版本号(serialVersionUID)以保持序列化数据的兼容性。如果没有显式声明,Java会自动生成一个版本号,但更改类结构可能导致反序列化...