`
lenjey
  • 浏览: 90853 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

对象序列化为何要定义serialVersionUID的来龙去脉

    博客分类:
  • J2SE
阅读更多
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到内存,等要用了,再还原到对象中,说白了,就是能将一个2进制文件变成内存中的对象。在JAVA中,要实现这种机制,只要实现Serializable接口就可以了,先看下面这个简单例子,serialVersionUID稍后引出。我们先定义一个简单的Person类,然后创建这个对象,最后序列化它到一个文件。
import java.io.Serializable;
 
public class Person implements Serializable {
   
    private String name;
   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
public class WhySerialversionUID {
 
public static void main(String[] args) throws Exception {
 
//这里是把对象序列化到文件       
Person crab = new Person();
crab.setName("Mr.Crab");
 
ObjectOutputStream oo = new ObjectOutputStream
    (new FileOutputStream("crab_file"));
oo.writeObject(crab);
oo.close();
 
//这里是把对象序列化到文件,我们先注释掉,一会儿用
//ObjectInputStream oi = new ObjectInputStream
//    (new FileInputStream("crab_file"));
//Person crab_back = (Person) oi.readObject();
//System.out.println("Hi, My name is " + crab_back.getName());
//oi.close();
 
    }
}

运行完后,我们发现有了一个crab_file文件,这个文件就保存这crab对象在内存中的形态。同样,我们把这部分代码注释掉,运行下面那段还原代码,发现,crab_file文件可以被转化为一个对象。

一切都那么顺利,但是如果在序列化之后,Person这个类发生了改变呢?比如,多了一个成员变量。我们做如下试验,还是先将对象序列化到一个文件中,之后在Person这个类中添加一个成员变量,如下:
import java.io.Serializable;
 
public class Person implements Serializable {
   
    private String name;
    //添加这么一个成员变量
    private String address;
   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

之后,我们再去运行一下还原,就发现运行出错了,会报如下错误:
Exception in thread “main” java.io.InvalidClassException: Person; local class incompatible: stream classdesc serialVersionUID = 8383901821872620925, local class serialVersionUID = -763618247875550322
意思就是说,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定serialVersionUID。之前,在我们的例子中,我们是没有指定serialVersionUID的,那么java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要这个文件多一个空格,得到的UID就会截然不同的,可以保证在这么多类中,这个编号是唯一的。所以,我们添加了一个字段后,由于没有显指定serialVersionUID,编译器又为我们生成了一个UID,当然和前面保存在文件中的那个不会一样了,于是就出现了2个号码不一致的错误。因此,只要我们自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法可以用,呵呵。但是serialVersionUID我们怎么去生成呢?你可以写1,也可以写2,都无所谓,但是最好还是按照摘要算法,生成一个惟一的指纹数字,eclipse可以自动生成的,jdk也自带了这个工具。一般写法类似于
private static final long serialVersionUID = -763618247875550322L;
分享到:
评论
5 楼 g_man1990 2017-04-06  
serialVersionUID可以继承么?
4 楼 TIMJAMES 2017-03-03  
  学习了!
3 楼 liu5840779 2014-10-22  
给力的楼主
2 楼 xunke515 2014-03-31  
例子不错。 顶个。
顺便问下“因此,只要我们自己指定了serialVersionUID,就可以在序列化后,去添加一个字段”
这个字段在后期还原之后的值是什么,默认值么?比如说int的默认值是0
1 楼 gdgzczh 2011-10-26  
      
学习了,很奇妙

相关推荐

    java 对象的序列化与反序列化

    1. **序列化标识符(SerialVersionUID)**:Java允许你为每个可序列化的类定义一个唯一的`serialVersionUID`,默认是由JVM根据类的结构计算出来的。如果类的版本更新导致结构变化,而此值未做更新,反序列化时会抛出`...

    java对象序列化和反序列化

    1. **定义**: Java对象序列化是将Java对象转换为字节流的过程,以便可以存储在磁盘上或在网络上传输。它允许我们将对象的状态保存下来,即使程序关闭,下次启动时也能恢复到之前的状态。 2. **接口**: 实现序列化的...

    Java对象序列化标准最新版

    `ObjectOutput`接口定义了将对象序列化的基本方法。任何实现了此接口的类都具备将Java对象写入对象流的能力。 **1.9 `ObjectInput`接口** `ObjectInput`接口定义了从对象流中读取对象的方法。任何实现了此接口的类...

    关于 Java 对象序列化您不知道的 5 件事

    Java对象序列化是Java平台的一项重要特性,它允许将对象的状态转换为字节流,以便存储、传输或恢复。在本文中,我们将深入探讨关于Java对象序列化你可能不知道的五件事情,这些知识点对于理解和优化你的Java应用程序...

    java对象序列化 传输 保存

    Java对象序列化是一种将Java对象转换为字节流的过程,以便可以存储这些对象或通过网络进行传输。这个过程是Java平台的核心特性,它允许开发者将复杂的对象结构持久化或者在网络间进行安全通信。序列化不仅可以用于...

    java 对象序列化

    Java对象序列化是一种将Java对象转换为字节流的过程,以便可以存储在磁盘上、在网络上传输或在任何其他需要持久化数据的场景中使用。这个过程涉及到两个主要概念:序列化(Marshalling)和反序列化(Unmarshalling)...

    android 对象序列化

    在标题"android 对象序列化"中,我们要讨论的是如何在Android环境中实现对象的序列化,并特别是在通过Intent传递对象的应用场景。 对象序列化在Android中的应用主要包括以下几个方面: 1. 数据持久化:当应用程序...

    Java对象序列化的秘密

    Java对象序列化是Java平台提供的一种机制,允许将对象的状态转换为字节流,以便存储在磁盘上、通过网络传输或在不同时间点恢复。这个过程涉及到将一个复杂的Java对象模型转换为简单的二进制表示,使得数据可以在不同...

    Java对象的序列化和反序列化实践

    对象序列化是将Java对象转换为字节流的过程,这使得对象可以被保存到磁盘上,或者在网络中进行传输。在Java中,要实现序列化,对象的类需要实现`java.io.Serializable`接口。例如,`ObjectSaver.java`文件可能包含一...

    对象的序列化和反序列化

    序列化是将一个对象转换为字节流的过程,而反序列化则是将字节流还原为原来的对象。这两个过程在许多场景下都非常有用,比如在网络传输、存储到磁盘或数据库、以及实现跨进程通信时。 首先,我们需要了解`...

    java serializable 序列化与反序列化

    2. **为什么需要序列化**:序列化有以下主要用途: - 持久化对象:将对象保存到磁盘,即使程序关闭后,也能恢复对象状态。 - 远程通信:在网络间传输对象,序列化可以使对象在不同JVM之间传递。 - 节省内存:通过...

    Java对象序列化

    Java对象序列化是Java平台提供的一种将对象的状态转化为字节流,以便存储或者在网络中传输的技术。这个过程称为序列化,而将字节流恢复为原来的对象状态则称为反序列化。序列化对于数据持久化、网络通信以及跨进程...

    Java对象的序列化与反序列化Java开发Java经验技巧

    Java对象的序列化与反序列化是Java编程中一项重要的技术,它允许我们将Java对象转换为字节流,便于存储、传输或者在网络间传递。这一过程对于数据持久化、跨进程通信(如RMI,Remote Method Invocation)以及分布式...

    Java 多次序列化对象到同壹個文件及反序列化的问题

    但要注意,即使保持`serialVersionUID`不变,对象的某些字段改变也可能导致反序列化异常。 2. **使用`ObjectOutputStream.writeUnshared()`**:此方法序列化一个对象,但不会写入其类描述信息,适合序列化多个对象...

    java序列化(Serializable)的作用和反序列化.doc

    下面是一个简单的序列化示例代码,展示了如何将一个`Box`对象序列化并存储到文件中,然后再从文件中读取出来: ```java package com.hotye.dchaoxiong.serializabletest; import java.io.FileInputStream; import ...

    对象流(序列化)

    - 网络传输:在网络应用中,可以将对象序列化为字节流,然后通过网络发送,接收端再进行反序列化。 - RMI(远程方法调用):序列化是RMI实现的基础,因为需要将对象从一个JVM传递到另一个JVM。 8. **序列化安全...

    实验一对象序列化的说明1

    对象序列化是Java中一种重要的功能,它使得对象的状态能够被持久化或者在网络中传输。虽然Java提供了一套默认的序列化机制,但通过自定义接口如FileSerializable,我们可以更好地控制序列化和反序列化的过程,满足...

    用序列化(Serializable)保存、读取对象

    这个接口是一个标记接口,没有定义任何方法,仅仅表示该类的对象可以被序列化。如果你希望一个类的实例能够被序列化,那么这个类就需要实现`Serializable`接口。 ```java public class MyClass implements ...

    Java序列化

    Java序列化是Java平台中的一种标准机制,允许将对象的状态转换为字节流,以便存储在磁盘上、通过网络进行传输或者在某些时候恢复原来的对象状态。这一过程包括两个主要步骤:对象的序列化(将对象转换为字节流)和反...

Global site tag (gtag.js) - Google Analytics