[实训]Java中的Serializable
来源:互联网 发布:林业优化投资率 编辑:程序博客网 时间:2024/03/28 23:00
在ssh项目中,不知为啥出现了运行时报错,报错提醒有一条是使类实现Serializable接口,然后我实现之后,再次运行竟然不报错了,很神奇,然后在网上找了这篇博客,学习一下Serializable。
Serizlizable 作用
对于一个存在于Java虚拟机中的对象来说,其内部的状态只保持在内存中。JVM停止之后,这些状态就丢失了。在很多情况下,对象的内部状态是需要被持久化下来的。提到持久化,最直接的做法是保存到文件系统或是数据库之中。比如:对象关系映射(Object-relational mapping)。对象序列化机制(object serialization)是Java语言内建的一种对象持久化方式,可以很容易的在JVM中的活动对象和字节数组(流)之间进行转换。除了可以很简单的实现持久化之外,另外序列化机制的另外一个重要用途是在远程方法调用中,用来对开发人员屏蔽底层实现细节。
基本的对象序列化
待序列化的Java类只需要实现Serializable接口即可。实际的序列化和反序列化工作是通过ObjectOuputStream和ObjectInputStream来完成的。ObjectOutputStream的writeObject方法可以把一个Java对象写入到流中,ObjectInputStream的readObject方法可以从流中读取一个Java对象。在写入和读取的时候,虽然用的参数或返回值是单个对象,但实际上操纵的是一个对象图,包括该对象所引用的其它对象,以及这些对象所引用的另外的对象。Java会自动帮你遍历对象图并逐个序列化。除了对象之外,Java中的基本类型和数组也是可以通过 ObjectOutputStream和ObjectInputStream来序列化的。
序列化时的对象替换
可能会希望在序列化的时候使用另外一个对象来代替当前对象。其中的动机可能是当前对象中包含了一些不希望被序列化的域。个订单系统中需要把订单的相关信息序列化之后,通过网络来传输。订单类Order引用了客户类Customer。在默认序列化的情况下,Order类对象被序列化的时候,其引用的Customer类对象也会被序列化,这可能会造成用户信息的泄露。
Private static class OrderReplace implements Serializable{
Private static final long serialVersionUID=47832438;
Private String orderId;
Public OrderReplace(Order order){
This.orderId = order.getId();
}
Private Object readResolve(){
//根据orderId查找Order 对象并返回。
}
Public Object writeReplace(){
Return new OrderReplace(this);
}
}
这个替换对象类OrderReplace只保存了Order的ID。在Order类的writeReplace方法中返回了一个OrderReplace对象。这个对象会被作为替代写入到流中。同样的,需要在OrderReplace类中定义一个readResolve方法,用来在读取的时候再转换回 Order类对象。这样对调用者来说,替换对象的存在就是透明的。
序列化和对象创建
在通过ObjectInputStream的readObject方法读取到一个对象之后,这个对象是一个新的实例,但是其构造方法是没有被调用的,其中的域的初始化代码也没有被执行。调用者并不知道对象是通过一般的new操作符来创建的,还是通过反序列化所得到的。解决的办法就是在类的readObject方法里面,再执行所需的对象初始化逻辑。对于一般的Java类来说,构造方法中包含了初始化的逻辑。可以把这些逻辑提取到一个方法中,在readObject方法中调用此方法。
版本更新
把一个Java对象序列化之后,所得到的字节数组一般会保存在磁盘或数据库之中。在保存完成之后,有可能原来的Java类有了更新,比如添加了额外的域。这个时候从兼容性的角度出发,要求仍然能够读取旧版本的序列化数据。在读取的过程中,当ObjectInputStream发现一个对象的定义的时候,会尝试在当前JVM中查找其Java类定义。这个查找过程不能仅根据Java类的全名来判断,因为当前JVM中可能存在名称相同,但是含义完全不同的Java 类。这个对应关系是通过一个全局惟一标识符serialVersionUID来实现的。通过在实现了Serializable接口的类中定义该域,就声明了该Java类的一个惟一的序列化版本号。JVM会比对从字节数组中得出的类的版本号,与JVM中查找到的类的版本号是否一致,来决定两个类是否是兼容的。对于开发人员来说,需要记得的就是在实现了Serializable接口的类中定义这样的一个域,并在版本更新过程中保持该值不变。当然,如果不希望维持这种向后兼容性,换一个版本号即可。该域的值一般是综合Java类的各个特性而计算出来的一个哈希值。可以通过Java提供的serialver命令来生成。在Eclipse中,如果Java类实现了Serializable接口,Eclipse会提示并帮你生成这个serialVersionUID。
Eg:
public class Book implements Serializable { //private static final long serialVersionUID = 5805574648076667828L; String name="chenlly"; //int vale = 7; //序列化写入文件 public void save() throws IOException { FileOutputStream f = new FileOutputStream("d://book.bin"); ObjectOutputStream oos = new ObjectOutputStream(f); oos.writeObject(this); oos.close(); } //反序列化从文件读取 public void read() throws IOException, ClassNotFoundException { FileInputStream f = new FileInputStream("d://book.bin"); ObjectInputStream ois = new ObjectInputStream(f); Book b = (Book) ois.readObject(); ois.close(); } public static void main(String []args){ Book b = new Book(); try { //序列化 b.save(); //读取 b.read(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
如果增加int vale = 7;,把b.save()注释掉,再次执行程序则会抛出如下异常。
java.io.InvalidClassException: cn.com.chenlly.Book; local class incompatible: stream classdesc serialVersionUID = -8127777334808352611, local class serialVersionUID = 6452469819260868051
java 默认情况下serialVersionUID是是综合Java类的各个特性而计算出来的一个哈希值。
两次的属性值一样导致serialVersionUID也不一样。
如果加上private static final long serialVersionUID = 5805574648076667828L则这个类都有一个唯一标识,两次的serialVersionUID不变。反序列化中还是不会报错。
如果把字符串改成int name=34; 执行逆-串行化操作时系统就不知道如何处理该值,显示出错误信息:java.io.InvalidClassException: cn.com.chenlly.Book; incompatible types for field name。
简而言之,如果文件中确实保存了所有必需的数据,那么仍有可能读取该文件,当然前提是必须处理好串行化的UID。
转载链接:http://blog.csdn.net/cdl2008sky/article/details/6747396
- [实训]Java中的Serializable
- java中的Serializable接口
- 关于java中的serializable
- java 中的Serializable
- Java中的Serializable
- Java中的Serializable浅谈
- Java中的Serializable
- java中的Serializable是什么
- java中的serializable接口
- java中的Serializable浅谈
- java中的Serializable接口作用
- java中的serializable接口详解
- 90001---浅谈Java中的Serializable
- Java中的序列化(Serializable)
- Java中的对象序列化Serializable
- Java中的Serializable浅谈,只是浅谈
- JAVA Serializable 类中的Serial Version ID
- java中的Serializable接口一:适用环境
- 41. First Missing Positive
- Linux常用的命令(一)
- HTTP协议详解(真的很经典)
- 阿里云windows server 2008 r2安装mysql失败
- 会议安排
- [实训]Java中的Serializable
- rpmbuild制作rpm 包
- 阅读笔记 >需求分析——检查需求内容
- WebView 笔记
- 【剑指offer-解题系列(58)】二叉树的下一个结点
- HTTP协议的头信息详解
- 人脸对齐之SDM论文解析
- 观察Linux行为
- Kotlin-05.包和导入(package & import)