Serializable and serialVersionUID

如果某个 class implements Serializable,Eclipse 会提示生成 serialVersionUID ,多数情况下,我都选择是。可这个东西到底是什么呢?

package com.home.demo;

import java.io.Serializable;

public class Item implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	private int data;

    public Item (int data) {
        this.data = data;
    }

    public int getData() {
        return data;
    }

}

Eclipse 再次提醒我要有serialVersionUID 。 好吧,既然是测试,给他个值1。

写一个测试类,试试 serialize and deserialize  Item

package com.home.demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class UIDTest {
	
	public void save2Disk(String fileName) throws IOException{
	File file = new File(fileName);
        FileOutputStream fos = new FileOutputStream(file);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        //set value to 101
        Item serializeMe = new Item(101); 
        oos.writeObject(serializeMe);
        oos.close();
        System.out.println("done!");
	}
	
	public void readFromDisk(String fileName) throws ClassNotFoundException, IOException{
	FileInputStream fis = new FileInputStream(fileName);
        ObjectInputStream ois = new ObjectInputStream(fis);
        Item dto = (Item) ois.readObject();
        System.out.println("data : " + dto.getData());
        ois.close();
	}

	/**
	 * @param args
	 * @throws IOException 
	 * @throws ClassNotFoundException 
	 */
	public static void main(String[] args) {
		UIDTest test = new UIDTest();
		String name = "D:/out.dat";
		try{
			// write file
			//test.save2Disk(name);   //--1
			
			test.readFromDisk(name);  // --2
		}catch(Exception e){
			e.printStackTrace();
		}
     
	}

}

运行结果

101

完全正确!


看看D盘,有个文件out.dat. 关闭写文件,直接读取 out.dat 

运行结果

101


试试把 serialVersionUID = 2L

private static final long serialVersionUID = 2L;

再运行

java.io.InvalidClassException: 
com.home.demo.Item; local class incompatible: 
stream classdesc serialVersionUID = 1, 
local class serialVersionUID = 2

噢。。。。 出错了!

根据 Java document, 

Serialization is for serializing instances, not classes. Static fields (methods are irrelevant since they are part of the class definition so they aren't serialized) will be reinitialized to whatever value they are set to when the class is loaded.

根据这个说法,Item不可能知道  serialVersionUID  的值,为什么会报错?

继续看文档! 

好吧 serialVersionUID  属于例外,这个值的确“get serialized”. 

ObjectOutputStream writes every time the value ofserialVersionUID to the output stream. 

ObjectInputStream reads it back and if the value read from the stream does not agree with the serialVersionUID value in the current version of the class, then it throws the InvalidClassException.

Moreover, if there is no serialVersionUID officially declared in the class to be serialized, compiler automatically adds it with a value generated based on the fields declared in the class.

假如你在机器A上serialize 了数据,然后送到B机器上deserialize ,需要一定的信息来帮忙确定数据的正确性。serialVersionUID  就是用于干这个活的。所以,Eclipse建议我们使用的serialVersionUID ,可以对serialization进行最简单的检验和控制。


再回来看看Eclipse的提示 

Eclipse中,提供两种方式让我们快速添加SerialVersionUid

add default serial version ID
Adds a default serial version ID to the selected type
Use this option to add a user-defined ID in combination with custom serialization code if the type did undergo structural change since its first release.

Default 值是1L, 在可兼容的前提下,可以保留旧版本号,如果不兼容,或者想让它不兼容,就手工递增版本号。

add generated serial version ID
Adds a generated serial version ID to the selected type
Use this option to add a compiler-generated ID if the type didnot undergo structural change since its first release.

根据类的结构产生的hash值。增减一个属性、方法等,都可能导致这个值产生变化。

适合场景

开发者认为每次修改类后就需要生成新的版本号,不想向下兼容,操作就是删除原有serialVesionUid声明语句,再自动生成一下。

个人认为default简单。第二种能够保证每次更改类结构后改变版本号,虽然看上去很cool,实际上让人很迷惑。

如何使用 serialVersionUID  ?

What you should do is to change serialVersionUID (for example increase it by 1 or make your IDE generate automatically a new value) every time there is some change in the definition of data stored in the class. For example if you change data types, variable names or add new data – hence every time you want to have ‘backward incompatibility’ for deserialization.



Reference

http://stackoverflow.com/questions/6429462/java-static-serialization-rules

http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html

http://stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it

http://www.javablogging.com/what-is-serialversionuid/

http://www.mkyong.com/java-best-practices/understand-the-serialversionuid/







转载于:https://my.oschina.net/u/1767744/blog/316422

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值