- 浏览: 148909 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (110)
- CoreJava (18)
- 待解决 (1)
- 数据结构 (3)
- 科普 (2)
- 网站 (1)
- DataBase (8)
- Access (1)
- Asp (1)
- JSP (1)
- 操作系统 (8)
- Tech (1)
- Linux (11)
- Career (5)
- MongoDB (1)
- Embedded (1)
- JavaScript (1)
- UltraIso (1)
- Linux命令 (1)
- DesignPattern (1)
- Ruby (13)
- Vim (1)
- 自考 (2)
- Github (5)
- zrProject (1)
- Emacs (4)
- Math (3)
- Ajax (1)
- 没看懂 (1)
- HTML (1)
- Philosophy (1)
- 软件 (1)
- 面试 (1)
- 考试报名 (3)
- Regex (1)
- 日语 (1)
- 生活 (1)
最新评论
java文件中为什么会有serialVersionUID 。
一些java类中为什么需要重载 serialVersionUID 属性。
在Java中,软件的兼容性是一个大问题,尤其在使用到对象串行性的时候,那么在某一个对象已经被串行化了,可是这个对象又被修改后重新部署了,那么在这种情况下, 用老软件来读取新文件格式虽然不是什么难事,但是有可能丢失一些信息。serialVersionUID 来解决这些问题,新增的serialVersionUID必须定义成下面这种形式:static final long serialVersionUID=-2805284943658356093L;。其中数字后面加上的L表示这是一个long值。 通过这种方式来解决不同的版本之间的串行话问题。
提纲:
━━━━━━━━
一、概述
二、Java串行化
三、引入版本编号
四、结束语
━━━━━━━━
一、概述
一 个程序正式发行出去之后,如果要增加一些新的功能,往往意味着同时要修改用户保存数据的方式,也就是必须更改程序保存文件的格式——通常是增加保存到文件 的数据。有些时候,文件格式必须作彻底的改动,以配合实现程序的新功能。从这个意义上看,文件格式的发展/变化总是和程序的功能改进相呼应。
但是,大多数情况下,把原有的数据格式一丢了事是行不通的。动物王国中,不能适应环境意味着死亡;软件领域也相似,新软件是否支持原有的数据格式很大程度上决定了用户是否升级。
不管软件新增/改进了多少功能,不管新的文件格式是多么完美,如果新软件不能利用原来的文件格式,用户一般不太会认可新软件。解决该问题的办法包括:
● 保留老代码来读取老文件。采用这种方案一般需要额外编写一些代码,把老文件转换成新的格式(一般地,最简单的办法是先把老文件的数据转换成新的内部对象, 然后利用现有的写入新版文件格式的对象)。这种办法的好处是既保留了原有的代码,又使它与新的文件格式兼容。但是,这种办法有时可能导致丢失部分数据,不 过总要比丢失全部数据好。
●使新版软件能够读/写老文件格式。这种办法工作量较大,因为程序的新版本一般会增加一些原来没有的功能,老的数据格式中通常缺乏新功能必需的某些数据。
当 新版软件对原来执行任务的方式作了根本性的变动时,丢失数据决非难得一见的偶然事件。如果新版软件采用和原来不同的方式达到同样的效果,原来的功能可能不 再有保留的必要。例如,如果一个程序原来用Swing做用户界面,现在把它改成了Web(浏览器)用户界面,原来的许多用户界面设置就不再有效。
又如,如果有一个邮件程序,原来用的是以文件夹为基础的索引,现在把它改成了以单词为基础的索引系统,在升级索引文件格式的过程中就有可能丢失许多信息;如果原来的索引文件保存了许多用户配置选项和优化措施,在新的索引系统中这些数据可能无法利用。
这 类问题没有绝对完美的解决办法,但是我们可以采取一些措施,使得升级文件格式带来的负面影响尽可能小。Java串行化(Serialization)有着 简单易用的特点,日益成为一种保存文件的重要手段,有鉴于此,下面我们就来看看在软件版本变更过程中,通过Java串行化保存的文件如何保持兼容性。
二、Java串行化
Java串行化有许多优点:
●容易使用。
●如果一个对象连接到其他对象,串行化机制会保存所有相关的对象。
●如果某个对象出现多次,串行化机制只保存一次。这一点极为重要,它不仅减小了文件空间,而且即使代码写得不是很老练,也不必担心会出现无限循环(一个不老练的例子是,用递归的方式保存各个对象,却又未能有效审计哪些对象已经保存,这时就有可能陷入永无终止的循环)。
遗憾的是,Java串行化机制定义的文件格式似乎很脆弱,只要稍微改动一下类的定义,原来保存的对象就可能无法读取。例如,下面是一个简单的类定义:
public class Save implements Serializable
{
String name;
public void save() throws IOException
{
FileOutputStream f = new FileOutputStream("foo");
ObjectOutputStream oos = new ObjectOutputStream(f);
oos.writeObject(this);
oos.close();
}
}
如果在这个类定义中增加一个域,例如final int val = 7;,再来读取原来保存的对象,就会出现下面的异常:
java.io.InvalidClassException:
Save; local class incompatible:
stream classdesc serialVersionUID = -2805284943658356093,
local class serialVersionUID = 3419534311899376629
上例异常信息中的数字串表示类定义里各种属性的编码值:
●类的名字(Save)。
●域的名字(name)。
●方法的名字(Save)。
●已实现的接口(Serializable)。
改 动上述任意一项内容(无论是增加或删除),都会引起编码值变化,从而引起类似的异常警报。这个数字序列称为“串行化版本统一标识符”(serial version universal identifier),简称UID。解决这个问题的办法是在类里面新增一个域serialVersionUID,强制类仍旧使用原来的UID。新增的域 必须是:
●static:该域定义的属性作用于整个类,而非特定的对象。
●final:保证代码运行期间该域不会被修改。
●long:它是一个64位的数值。
也就是说,新增的serialVersionUID必须定义成下面这种形式:static final long serialVersionUID=-2805284943658356093L;。其中数字后面加上的L表示这是一个long值。
当 然,改动之后的类不一定能够和原来的对象兼容。例如,如果把一个域的定义从String改成了int,执行逆-串行化操作时系统就不知道如何处理该值,显 示出错误信息:java.io.InvalidClassException: Save; incompatible types for field name。
Java串行化规范(http://java.sun.com/j2se/1.4.1/docs/guide/
serialization/spec/serialTOC.doc.html)提供了有关兼容的改动(http://java.sun.com/j2se/1.4.1/docs/
guide/serialization/spec/version.doc7.html)和不兼容改动(http://java.sun.com/j2se/1.4.1/docs/guide/
serialization/spec/version.doc8.html)的清单,这些清单指出了对类作了哪些改动之后仍可能读取原来串行化的数据。具体细节比较复杂,但了解其主要机制还是很容易的:
简而言之,如果文件中确实保存了所有必需的数据,那么仍有可能读取该文件,当然前提是必须处理好串行化的UID。
三、引入版本编号
许 多程序都在无意之中作出了这样的假设:这种文件格式是我要用到的最后一种格式,以后不再需要制定新的格式,现在要做的是处理好在此之前的各种格式。这种程 序会试图读取格式版本更高的文件,操作进行到一半才发现某些不能识别的数据,然后就是突然崩溃。如果文件包含了大量的元数据(描述文件本身的数据),处理 起来就要容易得多。
在Java中,每一个域都由其名称显式标明,只要文件的改动不是很大(只添加了域,没有被删除或作重大更改的域),可以想象,用老软件来读取新文件格式不是什么难事,虽然有可能丢失一些信息,但可以搞清楚文件的基本情况。
文件格式随着程序功能的改变而改变。理想情况下,程序应当做到既向后兼容(新的版本能够按照老版本的格式读取,甚至可能允许更新),同时做到向前兼容(较老的软件能够识别和处理新版的文件格式)。
通 常,文件的版本无法从表面上一眼看出。大多数程序不会因为文件的版本不同而更改文件扩展名,而且目前尚无统一的标记文件版本的办法。因此,有关文件格式的 版本声明只能在文件本身之内进行。如果你现在使用的文件格式还不包含版本声明,最好在下次把文件升级成一个不兼容的版本时马上加入版本标记,或者寻求一种 在当前文件格式中加入版本标记但不会带来负面影响的办法。
版本信息一般在文件的开头声明,这是因为程序必须在处理文件之前首先检查文件的版本,除非确定了文件的版本,否则不必读取文件的其余部分。
按照惯例,文件版本编号包含两个部分:主版本编号和次版本编号。一个特定版本的程序应当有最适合它处理的主-次版本号;主版本号变化意味着文件格式的重大变化,要继续使用已经非常困难,必须作出重大修改才能升级到新的版本。
文 件的主次版本号之前往往还可以加入另一项内容,称为“魔术数字”,它的作用就是保证程序处理的文件类型不会有误(因为文件扩展名有可能不能唯一地标明文件 类型)。例如,Java的类文件总是以下列字节内容开头(十六进制):CA FE BA BE。目前还没有这类数字的统一注册机构,不过UNIX在/etc/magic下提供了一个清单(但并不完整)。魔术数字一般有四个字节,取值范围很大, 所以一般不必担心会出现取值冲突的情形。
在编写和维护必须读/写文件的代码时,注意代码的向前/向后兼容性是非常必要的。在处理文件的代码中首先读取文件版本,然后根据版本号将文件剩余内容传递给适当的处理方法;如果文件的版本太老,已不再支持,程序应当给出明确的提示。
四、结束语
文 件格式设计是一个极其重要的话题,但本文还有许多细节问题尚未涉及。例如,对于大型文件,我们需要随机访问,而不是从前向后依次读取文件内容的顺序访问, 这样就不必为了访问文件最后几个字节而读取整个文件。无论是XML还是Java串行化对这类随机访问的支持都不是很理想,而且这类文件格式的发展变化比普 通文件更难管理,因为他们依赖于字节级的访问,稍微改动一下文件格式就可能导致不兼容。
如果要让文件具有ACID特性—— Atomicity、Consistency、Isolation和Durability,即原子性、一致性、隔离性、持久性,问题更加复杂。ACID与 事务的概念密切相关,支持多用户同时访问一个文件。对于这类文件,可以考虑采用某种小型的数据库系统,例如Birdstep或Sleepycat。不过这 已经进入了文件格式管理的另一个领域,既涉及到数据库管理软件的版本,也涉及到数据模式设计的版本。
撇开这些复杂的问题不谈,在实践中,很多时候我们只需简单的文件来保存数据,而且不会出现多用户并发访问,可以一次性地处理整个文件(或者至少适合使用顺序访问方式)。对于这些情形,最好在设计文件格式时就考虑版本问题,在日后的运行、维护中一定会带来不少方便。
发表评论
-
利用反射实现ORM
2012-03-28 13:37 987http://royzhou1985.iteye.com ... -
Eclipse插件安装
2012-03-28 09:29 908装载:http://gooss.org/are-two- ... -
Date & Calendar 类的使用
2012-03-27 14:19 666Java 语言的Calendar(日历),Date(日期 ... -
Java文件流 编码问题 - 读取文件时指定字符编码
2012-03-25 22:04 11537折磨了一天的问题,终于在黄昏的时候解决了,现在一吐为 ... -
打jar包
2012-02-04 17:12 749其实JAR文件的格式是ZIP ... -
JavaBean - Bound属性
2012-02-04 15:54 10004.4.3 Bound属性 Bound属性表示当该种 ... -
怎样在程序里获得一个空指针?
2012-01-28 15:56 6706.2 怎样在程序里获 ... -
制作可执行的Jar包
2012-01-22 16:35 738通常有两种,一种是制 ... -
Thread Local
2012-01-22 10:28 754What is Thread Local? Threa ... -
Jni介绍
2011-10-26 19:33 590http://baike.baidu.com/view/127 ... -
获取外网IP地址
2011-10-26 18:47 905访问 http://checkip.dyndns.org/ -
this 与 getSource() 细节
2011-10-14 19:33 702一个对象实例化之后,在它的方法体中出现的this就是指自身。a ... -
static变量生存周期
2011-10-13 22:38 934标准规定static变量保证在第一次使用前初始化,但是并不保证 ... -
String 引用类型与基本类型区别
2011-10-13 22:20 811String a="A"; Stri ... -
抽象类与接口的区别
2011-10-09 11:30 550首先,我们来看一下抽象类的概念,java编程思想中说“万物皆对 ... -
transient用法
2011-09-19 11:16 805Java的serialization提供了一种持久化对象实例的 ... -
例1.1 TextFileTest
2011-07-06 23:19 668package SectionIO; import java ...
相关推荐
那么,serialVersionUID到底是什么?它又是如何生成的?在本篇文章中,我们将详细地解释 serialVersionUID 的概念和用途。 首先,让我们来看看 serialVersionUID 的定义:serialVersionUID 是一个静态常量,它的...
在安装 GenerateSerialVersionUID 插件后,可以在 Inspections 设置页面中勾选 Serializable class without 'serialVersionUID',并且还可以在 Severity 中设置提示级别,如 Warning、Error 等,默认为 Warning。...
默认情况下,JVM会根据类的字段和方法自动生成一个`serialVersionUID`,但这种方式并不总是可靠,特别是当类结构有变动时。 为了更精确地控制序列化过程,开发者可以在类中显式声明一个`private static final long ...
`serialVersionUID` 可以有两种显示的生成方式: 1. **默认生成**:如 `private static final long serialVersionUID = 1L;`。 2. **自定义生成**:基于类名、接口名、成员方法及属性等信息生成一个 64 位的哈希值...
在 Java 序列化机制中,serialVersionUID 有两种显示的生成方式:一是默认的 1L,二是根据类名、接口名、成员方法及属性等来生成一个 64 位的哈希字段。 下面是一个简单的示例代码,演示了 serialVersionUID 在应用...
1. 默认生成:在没有显式声明`serialVersionUID`时,JVM会生成一个默认值,通常为1L。例如: ```java private static final long serialVersionUID = 1L; ``` 2. 自动计算:基于类的元数据(如类名、接口名、成员...
在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。 在IDEA中,有两...
1. 序列化版本验证:在反序列化时,JVM会将传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较。如果相同,说明是一致的,可以进行反序列化,否则会出现反序列化版本一致的异常,即...
三期第一张IO笔记 6
如果类的字段、方法或者类结构发生改变,导致序列化的字节流发生变化,那么自动生成的`serialVersionUID`也会更新。当反序列化时,如果发现接收到的`serialVersionUID`与当前类的不匹配,就会抛出`...
在上面的例子中,我们首先定义了一个实现了 Serializable 接口的类 Serializable01,该类中有一个私有的静态、长整型常量 serialVersionUID,並且有一个私有的 byte 字段 b。然后,在 main 方法中,我们首先将对象写...
序列化版本号serialVersionUID的作用_动力节点Java学院整理.
#### 为什么需要显式声明serialVersionUID? 如果序列化类没有显式声明`serialVersionUID`,则序列化运行时将根据类的各种细节自动计算一个默认的`serialVersionUID`值。然而,这种默认的计算方式对类的细节非常...
为什么阿里巴巴建议初始化HashMap的...为什么阿里巴巴禁止开发人员修改serialVersionUID字段的值?97 为什么阿里巴巴建议开发者谨慎使用继承?109 为什么阿里巴巴禁止使用count(列名)或count(常量)来替代count(*) ?111
为什么阿里巴巴禁止开发人员修改 serialVersionUID 字段的值? 97 为什么阿里巴巴建议开发者谨慎使用继承? 109 为什么阿里巴巴禁止使用 count( 列名 ) 或 count( 常量 ) 来替代 count(*) ? 111
然而,当序列化的对象在不同环境中被反序列化时,可能会遇到`serialVersionUID`不一致的问题。`serialVersionUID`是一个特殊的标识符,用于确保序列化和反序列化之间的兼容性。如果类的`serialVersionUID`在序列化和...
`GenerateSerialVersionUID`插件则是针对这个特殊需求开发的工具,帮助开发者自动为类生成`serialVersionUID`,避免手动设置带来的麻烦和潜在错误。本文将深入探讨`GenerateSerialVersionUID`及其在Java序列化中的...
- 链接对象:如果有对象之间的引用,会递归地序列化这些对象,直到所有需要的对象都被处理。 4. 反序列化过程: - 调用`ObjectInputStream.readObject()`:通过`ObjectInputStream`的`readObject()`方法读取对象...