Java序列化关键字-Serializable解析
Serializable意指序列化,即把Java对象转化为二进制字节序列,同样,反序列化则是把之前对象生成的二进制字节序列还原成Java对象。它的存在意义是什么?现在的网络架构和硬盘只能识别二进制字节,假如要直接把Java对象在网络上传输,或者直接存入硬盘里,人家是根本不识别的。所以如果要把对象在网络上进行传输或者写入文件里,序列化是前提。另外需要了解的是:Serializable这个接口并没有定义要求你来实现的方法,它属于一钟标识接口,加上它就只是为了告诉别人:哦,你是可序列化的~
Java中采用ObjectInputStream来反序列化文件里的字节还原成对象,采用ObjectOutputStream来将对象变成字节写入文件中。
下面定义一个对象:User
public class User implements Serializable{ private int id; private String name; public User() { // TODO Auto-generated constructor stub } public User(int id, String name) { super(); this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } }
下面开始写入文件里:
public static void main(String[] args) { // TODO Auto-generated method stub User user=new User(1111,"hello"); ObjectOutputStream oos=null; try { oos=new ObjectOutputStream(new FileOutputStream("E://user.txt")); oos.writeObject(user); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { oos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
假如未实现Serializable接口,会产生如下异常:

写入文件后,看看长什么样子:

嗯,很明显,根本看不懂。
接下来用ObjectInputStream读取:

简单的写入读取就是这些,接下来重点来了:实现Serializable接口,会有感叹号警示,如果想要去除它,需要添加一个默认的版本ID,或者添加一个根据类本身信息自动生成的版本ID:
private static final long serialVersionUID = -1928208351401916910L;//自动生成
那么它的作用是什么呢?serialVersionUID用于版本控制,用于保证同一个对象可以在反序列化过程中被载入。怎么理解?下面用代码来说话:
我在不生成serialVersionUID的情况下,在原来的user类里加一个字段age,继续执行刚才的反序列化,会有以下异常:

这是在告诉你,最初的的时候版本号是-192.....,而你增加了一个字段后版本号改变成另一个了,再次反序列化,流根本不认识你这个‘新’的类(其实只是原来的类增加了字段而已),所以抛出异常。好比你换个发型带个眼镜,你还是你,公司前台人员却觉得不是你本人把你拒之门外(当然没这么蠢的前台人员。。)
而如果你一开始就生成了这个序列号,无论后面怎样添加新的字段都是可以继续反序列化的。好比你刚一开始就录入了自己的指纹,即便怎么化妆打扮你依然是你,公司的门随意出入。
之前讲过的单例模式,除了枚举那种写法外,其余都是无法避免反序列化的,下面把User改成饿汉单例模式
public class User implements Serializable{ private static final long serialVersionUID = -1928208351401916910L; private int id; private String name; private int age; private User() { // TODO Auto-generated constructor stub } private static User user=new User(); public static User getUser(){ return user; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
执行反序列进行比较:

此时已经不再是同一个对象了。
最后还有几点需要注意:1,由于静态变量是类级别的,不是对象级别的,当你序列化一个对象的时候,是不能序列化静态变量的。
2,假如你的对象有个字段引用了其他对象,而这个对象对应的类并没有实现Serializable接口,那么这个字段将无法被序列化(会报错)。如果你想忽略它,就在字段前加上transient(短暂的)。
3,继承这方面也有一定说法,我就不总结了。详情请参考:http://www.oschina.net/translate/serialization-in-java
OK,感觉还不错,还是手生。

浙公网安备 33010602011771号