- 浏览: 58584 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (43)
- c学习 (2)
- C++学习 (0)
- Qt学习 (0)
- c# (0)
- ASP.NET (0)
- ,NET技术 (0)
- PHP (0)
- LAMP技术 (0)
- Java EE (3)
- java学习 (14)
- jsp学习 (7)
- web开发 (3)
- WINDOWS编程 (0)
- UNIX/LINUX编程 (0)
- 设计模式 (0)
- 数据结构与算法 (0)
- 数据库 (1)
- 计算机网络 (0)
- 多媒体 (1)
- 人工智能 (0)
- 软件工程 (0)
- 软件测试 (0)
- 项目管理 (0)
- 信息安全 (1)
- 服务器 (0)
- 编译原理 (0)
- 移动开发 (0)
- 机器学习与信息检索 (0)
- 分布式技术 (0)
- 网络编程 (0)
- 财务管理 (0)
- 市场分析 (0)
- 企业管理 (0)
- 人力资源 (0)
- 心里学 (0)
- 外语学习 (0)
- 励志文章 (0)
- 社交礼仪 (0)
- 影视欣赏 (0)
- 生活乐趣 (1)
- eclipse (3)
- html (2)
- 杂文 (1)
- 中文乱码 (4)
最新评论
-
jaystarba:
谢了 楼主
你的抛异常那句很给力!
java 空字符串与null区别
本文介绍Java序列化技术。
1.Java的"对 象序列化"
Java 的"对象序列化"能让你将一个实现了Serializable接口的对象转换成一组byte,这样日后要用这个对象时候,你就能把这些byte数据恢复出 来,并据此重新构建那个对象。这一点甚至在跨网络的环境下也是如此,这就意味着序列化机制能自动补偿操作系统方面的差异。也就是说,你可以 在 Windows机器上创键一个对象,序列化之后,再通过网络传到Unix机器上,然后在那里进行重建。你不用担心在不同的平台上数据是怎样表示 的, byte顺序怎样,或者别的什么细节。
对象序列化最聪明的一点是,它不仅能保存对象的副本,而且还会跟踪对象里面的reference,把它所引用的对象也保存起来,然后再 继续跟踪那些对象的 reference,以此类推。这种情形常被称为"单个对象所联结的'对象网'"。这个机制所涵盖的范围不仅包括对象的成员数据,而 且还包含数组里面的 reference。如果你要自己实现对象序列化的话,那么编写跟踪这些链接的程序将会是一件非常痛苦的任务。但是,Java的对象 序列化就能精确无误地 做到这一点,毫无疑问,它的遍历算法是做过优化的。
2.Object serialization的定义
Object serialization 允许你将实现了 Serializable接口的对象转换为字节序列,这些字节序列可以被完全存储以备以后重新生成原来的对象。
serialization不但可以在本机做,而且可以经由网络操作 (RMI)。这个好处是很大的----因为它自动屏蔽了操作系统的差异,字节顺序(用Unix下的c开发过网络编程的人应该知道这个概念)等。比如,在 Window平台生成一个对象并序列化之,然后通过网络传到一台Unix机器上, 然后可以在这台Unix机器上正确地重构这个对象。
Object serialization主要用来支持2种主要的特性:
Java的 RMI(remote method invocation).RMI允许象在本机上一样操作远程机器上的对象。当发送消息给远程对象时,就需要用到 serializaiton机制来发送参数和接收返回直。
Java的JavaBeans。Bean的状态信息通常是在设计时配置的。Bean的状态信息必须被存起来,以便当程序运行时能恢复这 些状态信息。这也需要serializaiton机制。
3.一般序列化实例
程序名称:SerializationDemo.java
程序主题:实现对象的序列化和反序列化
程序说明:该程序由实例化一个MyClass类的对象开始,该对象有三个 实例变量,类型分别为String、int、double,是希望存储和恢复的信息。
import java.io.Serializable;
class MyClass implements Serializable {
String s;
int i;
double d;
public MyClass(String s, int i, double d) {
this.s = s;
this.i = i;
this.d = d;
}
public String toString() {
return "s=" + s + ";i=" + i + ";d=" + d;
}
}
要想序列化对象,你必须先创建一个OutputStream,然后把它嵌 进ObjectOutputStream。这时,你就能用writeObject ( )方法把对象写入OutputStream了。读的时候,你得把 InputStream嵌到ObjectInputStream里面,然后再调用 readObject( )方法。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializationDemo {
public static void main(String args[]) {
FileInputStream in = null;
FileOutputStream out = null;
ObjectInputStream oin = null;
ObjectOutputStream oout = null;
MyClass object1 = new MyClass("Hello", -7, 2.7e10);
System.out.println("object1:" + object1);
// Object serialization
try {
out = new FileOutputStream("serial.txt");
oout = new ObjectOutputStream(out);
oout.writeObject(object1);
oout.close();
} catch (Exception e) {
System.out.println("Exception during serialization:" + e);
System.exit(0);
}
// Object deserialization
try {
MyClass object2;
in = new FileInputStream("serial");
oin = new ObjectInputStream(in);
object2 = (MyClass) oin.readObject();
oin.close();
System.out.println("object2:" + object2);
} catch (Exception e) {
System.out.println("Exception during deserialization:" + e);
System.exit(0);
} finally {
// … 此处省略
}
}
}
结果:
object1:s=Hello;i=-7;d=2.7E10
object2:s=Hello;i=-7;d=2.7E10
4.修改默认的序列化机制
在序列化的过程中,有些数据字段我们不想将其序列化,对于此类字段我们只 需要在定义时给它加上transient关键字即可,对于transient字段序列化机制会跳过不会将其写入文件,当然也不可被恢复。但有时我们想将某 一字段序列化,但它在SDK中的定义却是不可序列化的类型,这样的话我们也必须把他标注为transient,可是不能写入又怎么恢复呢?好在序列化机制 为包含这种特殊问题的类提供了如下的方法定义:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
private void writeObject(ObjectOutputStream out) throws IOException;
(注:这些方法定义时必须是私有的,因为不需要你显示调用,序列化机制会 自动调用的)使用以上方法我们可以手动对那些你又想序列化又不可以被序列化的数据字段进行写出和读入操作。
下面是一个典型的例子,java.awt.geom包中的 Point2D.Double类就是不可序列化的,因为该类没有实现Serializable接口,在我的例子中将把它当作LabeledPoint类中 的一个数据字段,并演示如何将其序列化。
import java.awt.geom.Point2D;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class LabeledPoint implements Serializable {
private String label;
transient private Point2D.Double point;
public LabeledPoint(String label, double x, double y) {
super();
this.label = label;
this.point = new Point2D.Double(x, y);
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();// 先 序列化对象
oos.writeDouble(point.getX());
oos.writeDouble(point.getY());
}
private void readObject(ObjectInputStream ois) throws IOException,
ClassNotFoundException {
ois.defaultReadObject();// 先 反序列化对象
double x = ois.readDouble() + 1.0;
double y = ois.readDouble() + 1.0;
point = new Point2D.Double(x, y);
}
public String toString() {
return getClass().getName() + "[ Label = " + label
+ ", point.getX() = " + point.getX() + ",
point.getY() = " + point.getY() + "]";
}
}
public class Test1 {
public static void main(String[] args) {
LabeledPoint label = new LabeledPoint("Book", 5.0, 5.0);
try {
System.out.println("before:\n" + label);
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("label.txt"));
oos.writeObject(label);
oos.close();
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("label.txt"));
LabeledPoint label1 = (LabeledPoint) ois.readObject();
ois.close();
System.out.println("after add 1.0:\n" + label1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:
before:
sample.LabeledPoint[ Label = Book, point.getX() = 5.0, point.getY() = 5.0]
after add 1.0:
sample.LabeledPoint[ Label = Book, point.getX() = 6.0, point.getY() = 6.0]
5.继承类序列化实例
当一个父类实现Serializable接口后,他的子类都将自动的实现 序列化。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class SuperC implements Serializable {// 父 类实现了序列化
int supervalue;
public SuperC(int supervalue) {
this.supervalue = supervalue;
}
public String toString() {
return "supervalue: " + supervalue;
}
}
class SubC extends SuperC {// 子 类
int subvalue;
public SubC(int supervalue, int subvalue) {
super(supervalue);
this.subvalue = subvalue;
}
public String toString() {
return super.toString() + " sub: " + subvalue;
}
}
public class Test2 {
public static void main(String[] args) {
SubC subc = new SubC(100, 200);
FileInputStream in = null;
FileOutputStream out = null;
ObjectInputStream oin = null;
ObjectOutputStream oout = null;
try {
out = new FileOutputStream("Test1.txt");
oout = new ObjectOutputStream(out);
oout.writeObject(subc); // 子 类序列化
oout.close();
oout = null;
in = new FileInputStream("Test1.txt");
oin = new ObjectInputStream(in);
SubC subc2 = (SubC) oin.readObject(); // 子类反序列化
System.out.println(subc2);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
// … 此处省略
}
}
}
结果:
supervalue: 100 sub: 200
可见子类成功的序列化/反序列化了。怎管让子类实现序列化看起来是一件很简 单的事情,但有的时候,往往我们不能够让父类实现Serializable接口,原因是有时候父类是抽象的(这并没有关系),并且父类不能够强制每个子类 都拥有序列化的能力。换句话说父类设计的目的仅仅是为了被继承。
要为一个没有实现Serializable接口的父类,编写一个能够序列化的子类要做两件事情:
其一、父类要有一个无参的constructor;
其二、子类要负责序列化(反序列化)父类的域。
我们将SuperC的Serializable接口去掉,而给 SubC加上Serializable接口。运行后产生错误:
java.lang.Error: Unresolved compilation problem:
Serializable cannot be resolved or is not a valid superinterface
at Serial.SubC.<init>(SubC.java:15)
at Serial.Test1.main(Test1.java:19)
Exception in thread "main"
我们改写这个例子:
abstract class SuperC{
int supervalue;
public SuperC(int supervalue) {
this.supervalue = supervalue;
}
public SuperC() {}//增加一个无参的constructor
public String toString() {
return "supervalue: " + supervalue;
}
}
class SubC extends SuperC implements Serializable{// 子 类
int subvalue;
public SubC(int supervalue, int subvalue) {
super(supervalue);
this.subvalue = subvalue;
}
public String toString() {
return super.toString() + " sub: " + subvalue;
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.defaultWriteObject();// 先 序列化对象
out.writeInt(supervalue);// 再序列化父类的域
}
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {
in.defaultReadObject();// 先 反序列化对象
supervalue = in.readInt();//再反序列化父类的域
}
}
运行结果证明了这种方法是正确的。在此处我们又用到 了 writeObject/ readObject方法,以代替默认的行为。我们在序列化时,首先调用了 ObjectOutputStream的 defaultWriteObject,它使用默认的序列化行为,然后序列化父类的域;反序列化的时候也一样。
6.实现Externalizable接 口
Externalizable 接口继承自Serializable接口,如果一个类实现了Externalizable接口,那么将完全由这个类控制自身的序列化行为。 Externalizable接口声明了两个方法:
public void readExternal(ObjectInput in) throws IOException , ClassNotFoundException;
public void writeExternal(ObjectOutput out) throws IOException;
前者负责序列化操作,后者负责反序列化操作。
在对实现了Externalizable接口的类的对象进行反序列化时, 会先调用类的不带参数的构造方法(回忆前两个例子,异曲同工),这是有别于默认反序列方式的。如果把类的不带参数的构造方法删除,或者把该构造方法的访问 权限设置为private、默认或protected级别,会抛 出 java.io.InvalidException: no valid constructor异常。
class ExternalDemo implements Externalizable { // ExternalDemo 类必须实现Externalizable接口
private String aString = "TEST";
private int num = 0;
public ExternalDemo() {}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(aString);
out.write(88); // 在 序列化的数据最后加个88
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
aString = (String) in.readObject();
num = in.read(); // 把 数字88加进来
}
public String toString() { // 测试
return ("String:"+aString + " int:"+num);
}
}
public class Test3 {
public static void main(String[] args) {
ExternalDemo eDemo = new ExternalDemo();
try {
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("test3.txt"));
oos.writeObject(eDemo); // writeExternal() 自动执行
oos.close();
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("test3.txt"));
ExternalDemo demo = (ExternalDemo) ois.readObject(); // readExternal()自动执行
System.out.print(demo);
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:
String:TEST int:88
7.可序列化类的不同版本的序列化兼容性
凡是实现Serializable接口的类都有一个表示序列化版本标识符 的静态变量:
private static final long serialVersionUID ;
以上serialVersionUID的取值是Java运行时环境根据类 的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。
类的serialVersionUID的默认值完全依赖于Java编译器 的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的 serialVersionUID,也有可能相同。为了提高 serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。显式地 定义serialVersionUID有两种用途:
在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;
在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本 具有不同的serialVersionUID。
8.总结Java序列化技术
如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存;
当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列 化;
当一个父类实现序列化,子类自动实 现序列化,不需要显式实现Serializable接口;
如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个 NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化;
并非所有的对象都可以序列化,,至于为什么不可以,有很多原因。
另见:http://wenku.baidu.com/view/cbdea8fdc8d376eeaeaa31ee.html
1.Java的"对 象序列化"
Java 的"对象序列化"能让你将一个实现了Serializable接口的对象转换成一组byte,这样日后要用这个对象时候,你就能把这些byte数据恢复出 来,并据此重新构建那个对象。这一点甚至在跨网络的环境下也是如此,这就意味着序列化机制能自动补偿操作系统方面的差异。也就是说,你可以 在 Windows机器上创键一个对象,序列化之后,再通过网络传到Unix机器上,然后在那里进行重建。你不用担心在不同的平台上数据是怎样表示 的, byte顺序怎样,或者别的什么细节。
对象序列化最聪明的一点是,它不仅能保存对象的副本,而且还会跟踪对象里面的reference,把它所引用的对象也保存起来,然后再 继续跟踪那些对象的 reference,以此类推。这种情形常被称为"单个对象所联结的'对象网'"。这个机制所涵盖的范围不仅包括对象的成员数据,而 且还包含数组里面的 reference。如果你要自己实现对象序列化的话,那么编写跟踪这些链接的程序将会是一件非常痛苦的任务。但是,Java的对象 序列化就能精确无误地 做到这一点,毫无疑问,它的遍历算法是做过优化的。
2.Object serialization的定义
Object serialization 允许你将实现了 Serializable接口的对象转换为字节序列,这些字节序列可以被完全存储以备以后重新生成原来的对象。
serialization不但可以在本机做,而且可以经由网络操作 (RMI)。这个好处是很大的----因为它自动屏蔽了操作系统的差异,字节顺序(用Unix下的c开发过网络编程的人应该知道这个概念)等。比如,在 Window平台生成一个对象并序列化之,然后通过网络传到一台Unix机器上, 然后可以在这台Unix机器上正确地重构这个对象。
Object serialization主要用来支持2种主要的特性:
Java的 RMI(remote method invocation).RMI允许象在本机上一样操作远程机器上的对象。当发送消息给远程对象时,就需要用到 serializaiton机制来发送参数和接收返回直。
Java的JavaBeans。Bean的状态信息通常是在设计时配置的。Bean的状态信息必须被存起来,以便当程序运行时能恢复这 些状态信息。这也需要serializaiton机制。
3.一般序列化实例
程序名称:SerializationDemo.java
程序主题:实现对象的序列化和反序列化
程序说明:该程序由实例化一个MyClass类的对象开始,该对象有三个 实例变量,类型分别为String、int、double,是希望存储和恢复的信息。
import java.io.Serializable;
class MyClass implements Serializable {
String s;
int i;
double d;
public MyClass(String s, int i, double d) {
this.s = s;
this.i = i;
this.d = d;
}
public String toString() {
return "s=" + s + ";i=" + i + ";d=" + d;
}
}
要想序列化对象,你必须先创建一个OutputStream,然后把它嵌 进ObjectOutputStream。这时,你就能用writeObject ( )方法把对象写入OutputStream了。读的时候,你得把 InputStream嵌到ObjectInputStream里面,然后再调用 readObject( )方法。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializationDemo {
public static void main(String args[]) {
FileInputStream in = null;
FileOutputStream out = null;
ObjectInputStream oin = null;
ObjectOutputStream oout = null;
MyClass object1 = new MyClass("Hello", -7, 2.7e10);
System.out.println("object1:" + object1);
// Object serialization
try {
out = new FileOutputStream("serial.txt");
oout = new ObjectOutputStream(out);
oout.writeObject(object1);
oout.close();
} catch (Exception e) {
System.out.println("Exception during serialization:" + e);
System.exit(0);
}
// Object deserialization
try {
MyClass object2;
in = new FileInputStream("serial");
oin = new ObjectInputStream(in);
object2 = (MyClass) oin.readObject();
oin.close();
System.out.println("object2:" + object2);
} catch (Exception e) {
System.out.println("Exception during deserialization:" + e);
System.exit(0);
} finally {
// … 此处省略
}
}
}
结果:
object1:s=Hello;i=-7;d=2.7E10
object2:s=Hello;i=-7;d=2.7E10
4.修改默认的序列化机制
在序列化的过程中,有些数据字段我们不想将其序列化,对于此类字段我们只 需要在定义时给它加上transient关键字即可,对于transient字段序列化机制会跳过不会将其写入文件,当然也不可被恢复。但有时我们想将某 一字段序列化,但它在SDK中的定义却是不可序列化的类型,这样的话我们也必须把他标注为transient,可是不能写入又怎么恢复呢?好在序列化机制 为包含这种特殊问题的类提供了如下的方法定义:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
private void writeObject(ObjectOutputStream out) throws IOException;
(注:这些方法定义时必须是私有的,因为不需要你显示调用,序列化机制会 自动调用的)使用以上方法我们可以手动对那些你又想序列化又不可以被序列化的数据字段进行写出和读入操作。
下面是一个典型的例子,java.awt.geom包中的 Point2D.Double类就是不可序列化的,因为该类没有实现Serializable接口,在我的例子中将把它当作LabeledPoint类中 的一个数据字段,并演示如何将其序列化。
import java.awt.geom.Point2D;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class LabeledPoint implements Serializable {
private String label;
transient private Point2D.Double point;
public LabeledPoint(String label, double x, double y) {
super();
this.label = label;
this.point = new Point2D.Double(x, y);
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();// 先 序列化对象
oos.writeDouble(point.getX());
oos.writeDouble(point.getY());
}
private void readObject(ObjectInputStream ois) throws IOException,
ClassNotFoundException {
ois.defaultReadObject();// 先 反序列化对象
double x = ois.readDouble() + 1.0;
double y = ois.readDouble() + 1.0;
point = new Point2D.Double(x, y);
}
public String toString() {
return getClass().getName() + "[ Label = " + label
+ ", point.getX() = " + point.getX() + ",
point.getY() = " + point.getY() + "]";
}
}
public class Test1 {
public static void main(String[] args) {
LabeledPoint label = new LabeledPoint("Book", 5.0, 5.0);
try {
System.out.println("before:\n" + label);
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("label.txt"));
oos.writeObject(label);
oos.close();
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("label.txt"));
LabeledPoint label1 = (LabeledPoint) ois.readObject();
ois.close();
System.out.println("after add 1.0:\n" + label1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:
before:
sample.LabeledPoint[ Label = Book, point.getX() = 5.0, point.getY() = 5.0]
after add 1.0:
sample.LabeledPoint[ Label = Book, point.getX() = 6.0, point.getY() = 6.0]
5.继承类序列化实例
当一个父类实现Serializable接口后,他的子类都将自动的实现 序列化。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class SuperC implements Serializable {// 父 类实现了序列化
int supervalue;
public SuperC(int supervalue) {
this.supervalue = supervalue;
}
public String toString() {
return "supervalue: " + supervalue;
}
}
class SubC extends SuperC {// 子 类
int subvalue;
public SubC(int supervalue, int subvalue) {
super(supervalue);
this.subvalue = subvalue;
}
public String toString() {
return super.toString() + " sub: " + subvalue;
}
}
public class Test2 {
public static void main(String[] args) {
SubC subc = new SubC(100, 200);
FileInputStream in = null;
FileOutputStream out = null;
ObjectInputStream oin = null;
ObjectOutputStream oout = null;
try {
out = new FileOutputStream("Test1.txt");
oout = new ObjectOutputStream(out);
oout.writeObject(subc); // 子 类序列化
oout.close();
oout = null;
in = new FileInputStream("Test1.txt");
oin = new ObjectInputStream(in);
SubC subc2 = (SubC) oin.readObject(); // 子类反序列化
System.out.println(subc2);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
// … 此处省略
}
}
}
结果:
supervalue: 100 sub: 200
可见子类成功的序列化/反序列化了。怎管让子类实现序列化看起来是一件很简 单的事情,但有的时候,往往我们不能够让父类实现Serializable接口,原因是有时候父类是抽象的(这并没有关系),并且父类不能够强制每个子类 都拥有序列化的能力。换句话说父类设计的目的仅仅是为了被继承。
要为一个没有实现Serializable接口的父类,编写一个能够序列化的子类要做两件事情:
其一、父类要有一个无参的constructor;
其二、子类要负责序列化(反序列化)父类的域。
我们将SuperC的Serializable接口去掉,而给 SubC加上Serializable接口。运行后产生错误:
java.lang.Error: Unresolved compilation problem:
Serializable cannot be resolved or is not a valid superinterface
at Serial.SubC.<init>(SubC.java:15)
at Serial.Test1.main(Test1.java:19)
Exception in thread "main"
我们改写这个例子:
abstract class SuperC{
int supervalue;
public SuperC(int supervalue) {
this.supervalue = supervalue;
}
public SuperC() {}//增加一个无参的constructor
public String toString() {
return "supervalue: " + supervalue;
}
}
class SubC extends SuperC implements Serializable{// 子 类
int subvalue;
public SubC(int supervalue, int subvalue) {
super(supervalue);
this.subvalue = subvalue;
}
public String toString() {
return super.toString() + " sub: " + subvalue;
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.defaultWriteObject();// 先 序列化对象
out.writeInt(supervalue);// 再序列化父类的域
}
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {
in.defaultReadObject();// 先 反序列化对象
supervalue = in.readInt();//再反序列化父类的域
}
}
运行结果证明了这种方法是正确的。在此处我们又用到 了 writeObject/ readObject方法,以代替默认的行为。我们在序列化时,首先调用了 ObjectOutputStream的 defaultWriteObject,它使用默认的序列化行为,然后序列化父类的域;反序列化的时候也一样。
6.实现Externalizable接 口
Externalizable 接口继承自Serializable接口,如果一个类实现了Externalizable接口,那么将完全由这个类控制自身的序列化行为。 Externalizable接口声明了两个方法:
public void readExternal(ObjectInput in) throws IOException , ClassNotFoundException;
public void writeExternal(ObjectOutput out) throws IOException;
前者负责序列化操作,后者负责反序列化操作。
在对实现了Externalizable接口的类的对象进行反序列化时, 会先调用类的不带参数的构造方法(回忆前两个例子,异曲同工),这是有别于默认反序列方式的。如果把类的不带参数的构造方法删除,或者把该构造方法的访问 权限设置为private、默认或protected级别,会抛 出 java.io.InvalidException: no valid constructor异常。
class ExternalDemo implements Externalizable { // ExternalDemo 类必须实现Externalizable接口
private String aString = "TEST";
private int num = 0;
public ExternalDemo() {}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(aString);
out.write(88); // 在 序列化的数据最后加个88
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
aString = (String) in.readObject();
num = in.read(); // 把 数字88加进来
}
public String toString() { // 测试
return ("String:"+aString + " int:"+num);
}
}
public class Test3 {
public static void main(String[] args) {
ExternalDemo eDemo = new ExternalDemo();
try {
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("test3.txt"));
oos.writeObject(eDemo); // writeExternal() 自动执行
oos.close();
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("test3.txt"));
ExternalDemo demo = (ExternalDemo) ois.readObject(); // readExternal()自动执行
System.out.print(demo);
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:
String:TEST int:88
7.可序列化类的不同版本的序列化兼容性
凡是实现Serializable接口的类都有一个表示序列化版本标识符 的静态变量:
private static final long serialVersionUID ;
以上serialVersionUID的取值是Java运行时环境根据类 的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。
类的serialVersionUID的默认值完全依赖于Java编译器 的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的 serialVersionUID,也有可能相同。为了提高 serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。显式地 定义serialVersionUID有两种用途:
在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;
在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本 具有不同的serialVersionUID。
8.总结Java序列化技术
如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存;
当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列 化;
当一个父类实现序列化,子类自动实 现序列化,不需要显式实现Serializable接口;
如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个 NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化;
并非所有的对象都可以序列化,,至于为什么不可以,有很多原因。
另见:http://wenku.baidu.com/view/cbdea8fdc8d376eeaeaa31ee.html
发表评论
-
内存管理与垃圾收集(四)
2010-11-30 12:47 879... -
内存管理与垃圾收集(三)
2010-11-30 11:22 708... -
内存管理与垃圾收集(二)
2010-11-30 10:20 629内存管理 ... -
内存管理与垃圾收集(一)
2010-11-30 09:48 728内存 ... -
java读写xml文件的方法
2010-11-07 11:11 849在java环境下读取xml文件的方法主要有4种:DOM、SAX ... -
java关于23种设计模式的有趣见解
2010-11-07 10:59 626创建型模式 1、FACTORY—追MM少不了请吃饭了,麦当劳 ... -
java 空字符串与null区别
2010-11-03 15:05 7931java 空字符串与null区别 " " ... -
java中replace和replaceAll的区别
2010-10-28 11:51 718replace和replaceAll是JAVA中常用的替换字符 ... -
JAVA几个常见错误简析
2010-10-28 11:50 7661,空指针错误 java.lang.NullPointerEx ... -
JAVA几个常见错误简析
2010-10-28 11:50 7171,空指针错误 java.lang.NullPointerEx ... -
eclipse以及step into step over step return的区别
2010-10-27 17:42 1464首先来讲一下step into ste ... -
java调用chm帮助文件
2010-10-27 16:53 893import java.io.*; public class ... -
浅析Java语言中两种异常的差别
2010-10-09 19:31 651Java提供了两类主要的异常:runtime exceptio ...
相关推荐
学习Java序列化,里面包含一份PPT以及相应的源码演示
java序列化(Serializable)的作用和反序列化.doc 有详细的讲解哦。 在什么地方用的到都有说明的.
java 序列化详细解释 很详细 适用于高级软件开发者
java序列化代码示例,详细讲解序列化作用于使用注意规则项!!!
Java SE编程入门教程 java序列化(共14页).pptx Java SE编程入门教程 java异常(共57页).pptx Java SE编程入门教程 java正则(共8页).pptx Java SE编程入门教程 properties(共3页).pptx Java SE编程入门教程 ...
序列化是干什么的? 简单说就是为了保存在内存中的各种对象的状态(也就是实例...虽然你可以用你自己的各种各样的方法来保 存object states,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。
大家请看Java的序列化结构有不足的地方请指教也希望指出不足的地方。
java序列化和反序列化java序列化和反序列化java序列化和反序列化
将java数据 序列化成PHP的格式 a:4:{s:6:"title2";s:13:"这是标题2";s:6:"title3";s:13:"这是标题3";s:5:"title";s:13:"这是标题1";s:6:"title4";s:13:"这是标题4";} 或者a:1:{i:0;a:1:{s:4:"name";s:10:"这是1321";...
在应用java进行c-s开发的时候,尤其涉及到图片和视频之间的传输时,需要用序列化和反序列化技术,希望对您有帮助
该资源提供了java常见的三个序列化框架,分别是:JBoss Marshalling,messagePack,protobuf-java
07-Java序列化面试题(10题)-新增
java 序列化,java 序列化,java 序列化,java 序列化,java 序列化,java 序列化
NULL 博文链接:https://hw1287789687.iteye.com/blog/2190768
E043-服务漏洞利用及加固-利用Java序列化漏洞进行渗透测试
java序列化是面试中经常涉及的重要主题之一。对Java序列化的深入了解不仅可以展示你的编程技能,还能体现出你对Java核心概念的掌握。本文精选了20道复杂的Java序列化面试题,并提供了详细的解析,旨在帮助你更好地...
Java序列化与反序列化 Java序列化与反序列化 Java序列化与反序列化 Java序列化与反序列化 Java序列化与反序列化
Java序列化机制(2)- serialVersionUID 实验 http://blog.csdn.net/suileisl/article/details/16991753
android(包括java)序列化一个对象传给php去做处理,或是接到php的序列化的对象在java中做处理的工具jar包以及使用方法. 使用方法: byte[] b = null; b = PHPSerializer.serialize(一个对象);//将一个对象序列化后返回...
详细讲解了java的序列化用处、原理、算法、如何实现。希望能帮到大家。