当对象要持久化到数据库,文件系统,或者网络传输时,说白了 就是流化时 要实现 Serializable接口 这个接口什么都没有,网络传言是个标识。
当你用eclipse开发需要流化的bean时 提示你 The serializable class Apple does not declare a static final serialVersionUID field of type long
这个东西是干什么的,今天做了个实验,探究了下。
大家都喜欢苹果 就弄个苹果类吧
package com.dic.obj;
import java.io.Serializable;
public class Apple implements Serializable{
/**
*
*/
private static final long serialVersionUID = 2L;//注意这里
private int size;
private String color;
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
然后我实例个类然后把它写到本地文件系统。
package com.dic.obj;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class Client {
public static void main(String[] args) throws IOException
{
System.out.println("hello world");
OutputStream out=new FileOutputStream("myapple");
ObjectOutputStream objout=new ObjectOutputStream(out);
Apple a=new Apple();
a.setColor("red");
a.setSize(5);
/*Pear p=new Pear();
p.setColor("yellow");
p.setSize(3);*/
objout.writeObject(a);
//objout.writeObject(p);
objout.close();
out.close();
}
}
然后我在读出来
package com.dic.obj;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
public class ReadObj {
public static void main(String args[]) throws IOException, ClassNotFoundException
{
System.out.println("hello world");
InputStream in=new FileInputStream("myapple");
@SuppressWarnings("resource")
ObjectInputStream inobj = new ObjectInputStream(in);
Apple a=(Apple) inobj.readObject();
//Pear p=(Pear) inobj.readObject();
System.out.println(a.getColor());
//System.out.println(p.getColor());
}
}
这是正确的,当我改一下apple的
serialVersionUID
</pre><pre name="code" class="java">
改成1L
再读一遍的时候hello world
Exception in thread "main" java.io.InvalidClassException: com.dic.obj.Apple; local class incompatible: stream classdesc serialVersionUID = 2, local class serialVersionUID = 1
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:560)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1599)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1494)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1748)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1327)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:349)
at com.dic.obj.ReadObj.main(ReadObj.java:29)
报错了 ,两个对象不兼容 一个是1L 一个是2L
再如 我把这个字段注释掉再读
hello world
Exception in thread "main" java.io.InvalidClassException: com.dic.obj.Apple; local class incompatible: stream classdesc serialVersionUID = 2, local class serialVersionUID = -6942525583000496744
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:560)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1599)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1494)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1748)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1327)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:349)
at com.dic.obj.ReadObj.main(ReadObj.java:29)
local的这个为-6942525583000496744 这个是怎么来的 呢 这个虚拟机自己算出来的 再流化的时候加进去的
所以这个字段,还是不写的,不写虚拟机给你算出来,如果两个类不一致,肯定会有异常,若是一样自这个两个类必定是一个 版本,具体这个数字怎么加上去的,还得再研究研究,另外原来没有注意到,为什么会有这个没有这个行不行,其实错误提示很明显了,因为用这个来判别写对象和读对象像时,用的是不是同一个class。
总之自己写的还是柴火 jdk说明才是王道
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException
。可序列化类可以通过声明名为 "serialVersionUID"
的字段(该字段必须是静态 (static)、最终 (final) 的 long
型字段)显式声明其自己的 serialVersionUID:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过, 强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的
InvalidClassException
。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用
private
修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。
另外可以把多个对象写到一个流了,然后分别读出来。
感谢批评指正