转自:http://www.cnblogs.com/gw811/archive/2012/10/10/2718331.html

Java API中java.io.Serializable接口源码:

public interface Serializable {

}

类通过实现java.io.Serializable接口可以启用其序列化功能。未实现次接口的类无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。

  Java的"对象序列化"能让你将一个实现了Serializable接口的对象转换成byte流,这样日后要用这个对象时候,你就能把这些byte数据恢复出来,并据此重新构建那个对象了。

  要想序列化对象,你必须先创建一个OutputStream,然后把它嵌进ObjectOutputStream。这时,你就能用writeObject()方法把对象写入OutputStream了。

  writeObject()方法负责写入特定类的对象的状态,以便相应的 readObject()方法可以还原它。通过调用 out.defaultWriteObject 可以调用保存 Object 的字段的默认机制。该方法本身不需要涉及属于其超类或子类的状态。状态是通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream 来保存的。

  读的时候,你得把InputStream嵌到ObjectInputStream里面,然后再调用readObject()方法。不过这样读出来的,只是一个Object的reference,因此在用之前,还得先下传。readObject() 方法负责从流中读取并还原类字段。它可以调用 in.defaultReadObject 来调用默认机制,以还原对象的非静态和非瞬态字段。  defaultReadObject()方法使用流中的信息来分配流中通过当前对象中相应命名字段保存的对象的字段。这用于处理类发展后需要添加新字段的情形。该方法本身不需要涉及属于其超类或子类的状态。状态是通过使用
writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream 来保存的。

  在序列化时,有几点要注意的:

  1:当一个对象被序列化时,只保存对象的非静态成员变量(包括声明为private的变量),不能保存任何的成员方法和静态的成员变量。

  2:如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被序列化。

  3:如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。

  1、序列化是干什么的?

  简单说就是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保存Object States,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。

  2、什么情况下需要序列化

  a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;

  b)当你想用套接字在网络上传送对象的时候;

  c)当你想通过RMI传输对象的时候;

  3、当对一个对象实现序列化时,究竟发生了什么?

  在没有序列化前,每个保存在堆(Heap)中的对象都有相应的状态(state),即实例变量(instance ariable)比如:

Foo myFoo = new Foo();
myFoo .setWidth(37);
myFoo.setHeight(70);

当通过下面的代码序列化之后,MyFoo对象中的width和Height实例变量的值(37,70)都被保存到foo.ser文件中,这样以后又可以把它从文件中读出来,重新在堆中创建原来的对象。当然保存时候不仅仅是保存对象的实例变量的值,JVM还要保存一些小量信息,比如类的类型等以便恢复原来的对象。

FileOutputStream fs = new FileOutputStream("foo.ser");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(myFoo);

4、实现序列化(保存到一个文件)的步骤

a)Make a FileOutputStream

  java 代码

  FileOutputStream fs = new FileOutputStream("foo.ser");

  b)Make a ObjectOutputStream

  java 代码

  ObjectOutputStream os = new ObjectOutputStream(fs);

  c)write the object

  java 代码

  os.writeObject(myObject1);

  os.writeObject(myObject2);

  os.writeObject(myObject3);

  d) close the ObjectOutputStream

  java 代码

  os.close();

  5、举例说明

public class Box implements Serializable {
private static final long serialVersionUID = -3450064362986273896L; private int width;
private int height; public static void main(String[] args) {
Box myBox=new Box();
myBox.setWidth(50);
myBox.setHeight(30);
try {
FileOutputStream fs=new FileOutputStream("F:\\foo.ser");
ObjectOutputStream os=new ObjectOutputStream(fs);
os.writeObject(myBox);
os.close();
FileInputStream fi=new FileInputStream("F:\\foo.ser");
ObjectInputStream oi=new ObjectInputStream(fi);
Box box=(Box)oi.readObject();
oi.close();
System.out.println(box.height+","+box.width);
} catch (Exception e) {
e.printStackTrace();
}
} public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}

6、相关注意事项

  a)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

  b)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

  c)并非所有的对象都可以序列化,至于为什么不可以,有很多原因了,比如:

  1.安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输 等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。

  2. 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现。

  serialVersionUID

  序列化运行时使用一个称为 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 值的要求。

java.io.Serializable浅析的更多相关文章

  1. java.io.Serializable 序列化接口

    什么是序列化.反序列化? Serialization(序列化)是一种将对象以一连串的字节描述的过程: 反序列化deserialization是一种将这些字节重建成一个对象的过程. 序列化通俗一点说就是 ...

  2. java.io.Serializable 序列化问题

    java.io.Serializable 序列化问题 Person.java package a.b.c; public class Person implements java.io.Seriali ...

  3. java.io.serializable

    为什么要实现 java.io.serializable? 简单点:“好处就是将来项目如果要做集群的话,就实现java.io.serializable接口”

  4. Teacher implements java.io.Serializable

    package JBJADV003; public class Teacher implements java.io.Serializable{ private String name; privat ...

  5. Student implements java.io.Serializable

    package JBJADV003; public class Student implements java.io.Serializable { private String name; priva ...

  6. java.io.Serializable 序列化问题【原】

    java.io.Serializable 序列化问题 Person.java package a.b.c; public class Person implements java.io.Seriali ...

  7. cause: java.lang.IllegalStateException: Serialized class com.taotao.pojo.TbItem must implement java.io.Serializable

    HTTP Status 500 - Request processing failed; nested exception is com.alibaba.dubbo.rpc.RpcException: ...

  8. spring+jax 出现java.io.Serializable is an interface, and JAXB can't handle interfaces

    spring+jax 出现java.io.Serializable is an interface, and JAXB can't handle interfaces 原因是我的webservice方 ...

  9. JDK1.8 java.io.Serializable接口详解

    java.io.Serializable接口是一个标志性接口,在接口内部没有定义任何属性与方法.只是用于标识此接口的实现类可以被序列化与反序列化.但是它的奥秘并非像它表现的这样简单.现在从以下几个问题 ...

随机推荐

  1. 根据不同的分辨率调用不同的css

    var Other1600 = "css_1600.css"; var Other1440 = "css_1440.css"; var Other1366 = ...

  2. js中的script标签

    在页面中用script标签引入javascript文件(<script type="text/javascript" src="js文件地址">&l ...

  3. 剑指offer系列42---二叉树深度

    [题目]输入一棵二叉树,求该树的深度. * 从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. package com.exe9.offer; /** * [题 ...

  4. 【设计模式】装饰者模式(Decorator)

    装饰者模式 动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案. Java I/O中的装饰类 示例:coffee装饰者模式类图 顶层超类 被装饰组件-被装饰者 装饰者抽象类 ...

  5. 黄聪:利用OpenXml生成Word2007文档(转)

    原文:http://blog.csdn.net/francislaw/article/details/7568317 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 一Op ...

  6. PLSQL_基础系列11_递归和层次查询CONNECT BY(案例)

    2015-05-31 Created By BaoXinjian

  7. PLSQL_数据泵导入进度查看Impdp/Expdp Status(案例)

    20150701 Created By BaoXinjian

  8. mysql5.6优化建议

    这篇文章主要介绍了MySQL5.6基本优化配置,详细分解了MySQL5.6需要优化的配置项,最终给出了一个优化案例,需要的朋友可以参考下     随着 大量默认选项的改进, MySQL 5.6比以前版 ...

  9. semanage: 未找到命令

    [root@hn ~]# semanage port -l|grep ssh-bash: semanage: 未找到命令 yum -y install policycoreutils-python

  10. Hololens开发笔记之Gaze凝视射线

    凝视是HoloLens首要输入方式,形式功能类似于桌面系统的光标,用于选择操作全息对象.然而在Unity中并没有明确的Gaze API或者组件. 概念上来说,Gaze是通过用户头部两眼之间发出一条向前 ...