- 浏览: 45854 次
- 性别:
- 来自: 深圳
最新评论
-
aindf0128:
ruanchengui1 写道thanks 让我恍然大悟 ...
ORACLE语句在Java代码中执行insert操作时报错:ORA-00911: 无效字符 -
ruanchengui1:
thanks 让我恍然大悟 问题解决啦.....特地上来 ...
ORACLE语句在Java代码中执行insert操作时报错:ORA-00911: 无效字符 -
刀枪剑戟:
授权这样就行了吧:
RemoteMethodServ ...
如何在eclipse中直接调用windchill的API
探讨对象次第读写(Serialization)
一. 对象次第读写 1. 实现对象的serialize操作 1.1. Serializable接口 只要让一个类实现出Serializable接口,就可对它的对象进行serialize操作了。Serializable接口仅仅是一个标志性接口,不具有任何的函数。也就是说,只要一个类实现了Serializable(在类名后加“implements Serializable”),那么那个类就可以进行Serialize操作了。 1.2. 对象所包含的对象的Serialization 1) Java库中的对象,如String,都实现了Serializable接口,所以它们都可进行serialization操作。 2) 对一个对象进行Serialize操作时,不仅会把对象在内存中的数据保存下来,还会把对象中所包含的可serialize成员对象也保存下来。如果对象中包含了没有实现Serializable接口的成员对象,那将在尝试对对象进行Serialize操作时,将发生错误。 3) 对一个Serializable对象进行次第读取时,并不会调用任何构造函数(包括default构造函数)。这是因为对象中的所有数据都是通过InputStream读取的数据来恢复的,所有不用通过构造函数来进行初始化。
import java.io.*; class Data implements Serializable{//(1) private int i; Data(int x) { i = x; } public String toString(){ return Integer.toString(i); } } class Worm implements Serializable{ private static int r(){ return (int)(Math.random() * 10); } //(2) private Data[] d = { new Data(r()), new Data(r()), new Data(r()) }; private Worm next; private char c; Worm(int i, char x){ System.out.println(" Worm constructor: " + i); c = x; if(--i > 0) next = new Worm(i, (char)(x + 1)); //(3) } Worm(){ System.out.println(" Default constructor " ); } public String toString(){ String s = ":" + c + "("; for(int i=0; i<d.length; i++) s += d[i].toString(); s += ")"; if(next!=null) s += next.toString(); return s; } } public class TestSerialization { public static void main(String[] args) throws ClassNotFoundException, IOException{ Worm w = new Worm(6, 'a'); System.out.println("w = " + w); ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("F:\\nepalon\\Worm.out")); out.writeObject("Worm storage"); out.writeObject(w); //(5) out.close(); ObjectInputStream in = new ObjectInputStream( new FileInputStream("F:\\nepalon\\Worm.out")); String s = (String)in.readObject(); //(4) Worm w2 = (Worm)in.readObject(); //(6) System.out.println(s + " , w2 = " + w2); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out2 = new ObjectOutputStream(bout); out2.writeObject("Worm storage"); out2.writeObject(w); out2.flush(); ObjectInputStream in2 = new ObjectInputStream( new ByteArrayInputStream( bout.toByteArray())); s = (String)in2.readObject(); Worm w3 = (Worm)in2.readObject(); System.out.println(s + " , w3 = " + w3); } }
运行结果为: Worm constructor: 6 Worm constructor: 5 Worm constructor: 4 Worm constructor: 3 Worm constructor: 2 Worm constructor: 1 w = :a(993):b(769):c(379):d(532):e(151):f(481) Worm storage , w2 = :a(993):b(769):c(379):d(532):e(151):f(481) Worm storage , w3 = :a(993):b(769):c(379):d(532):e(151):f(481) 代码(2)合成了一个Date数组;代码(3)用类似递归的方法生成了一 个Worm对象链。由结果可见Worm对象的成员Data数组及由Worm对象所产生的Worm对象链都能被很好的保存了下来。代码(4)则证明了Java库的类型都实现了Serializable接口的。 如果去掉(1)处代码,不让class Data实现Serializable接口,那么当调用writeObject()(如代码(5))来保存对象时,将产生NotSerializableException异常,因为在保存Worm对象时会去保存它的所有成员对象,但Data是不能Serialize的,所以会产生异常。 4) 进行次第读取时,在执行读取操作的class中一定要能找到相应的class文件。 在上面的代码中,如果class TestSerialization和class Worm分别处于两个不同的文件中,那么在代码(6)中执行了次第读取操作来还原一个对象时,就要确保在TestSerialization所在的文件中能找到Worm所在的文件,否则会产生ClassNotFoundException异常。
1.3. 关键字transient 当一个成员被声明为transient时,在对象被保存的时候,该成员将不被保存。
class Blip3 implements Serializable{ int i; String s1; transient String s2; public Blip3(String x, int a){ System.out.println("Blip3(String x, int a)"); //在non-default构造函数中初始化i、s1和s2 i = a; s1 = x; s2 = x; } public String toString(){ String s22 = (s2==null)?"s2 is null":s2; return "s1 = " + s1 + " , s2 = " + s22 + ", i = " + i; } } public class TestSerialization{ public static void main(String[] args) throws ClassNotFoundException, IOException{ System.out.println("Constructor Object: "); Blip3 b3 = new Blip3("A String", 47); System.out.println(b3); ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("F:\\nepalon\\test\\Blip3.out")); out.writeObject(b3); out.close(); ObjectInputStream in = new ObjectInputStream( new FileInputStream("F:\\nepalon\\test\\Blip3.out")); System.out.println("Recovering Object: "); b3 = (Blip3)in.readObject(); System.out.println(b3); } }
运行结果为: Constructor Object: Blip3(String x, int a) s1 = A String , s2 = A String, i = 47 Recovering Object: s1 = A String , s2 = s2 is null, i = 47 由于s2被声明为transient,所以它将不被保存。
2. 通过Externalizable接口来实现次第读写 通过实现了Externalizable接口来产生Serialize功能,我们将取得更大的控制权。 2.1. 通过实现了Externalizable接口来产生Serialize功能 1) 在保存对象时不会保存任何成员对象。但我们可以手工保存成员对象(下面将讲到)。 2) Default构造函数必须为public。因为在次第读取对象时,会调用default构造函数。因为对象中的成员对象不一定会被保存,所以要通过构造函数来进行初始化。 3) Extrenalizable接口有writeExternal(ObjectOutput)和readExternal(ObjectInput)两个函数。在对实现了Externalizable接口的类进行次第读写时,会调用这两个函数。但是在恢复对象时,是先调用default构造函数再调用readExternal()函数的。
import java.io.*; class Blip1 implements Externalizable{ public Blip1(){ //(1) System.out.println("Blip1 Constructor"); } public void writeExternal(ObjectOutput out) throws IOException{ System.out.println("Blip1.writeExternal"); } public void readExternal(ObjectInput in) throws IOException{ System.out.println("Blip1.readexternal"); } } class Blip2 implements Externalizable{ Blip2(){ //(2) System.out.println("Blip2 Constructor"); } public void writeExternal(ObjectOutput out) throws IOException{ System.out.println("Blip2.writeExternal"); } public void readExternal(ObjectInput in) throws IOException{ System.out.println("Blip2.readexternal"); } } public class TestSerialization{ public static void main(String[] args) throws ClassNotFoundException, IOException{ System.out.println("Constructor Object: "); Blip1 b1 = new Blip1(); Blip2 b2 = new Blip2(); ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("F:\\nepalon\\Blips.out")); System.out.println("Saveing Object: "); out.writeObject(b1); out.writeObject(b2); out.close(); ObjectInputStream in = new ObjectInputStream( new FileInputStream("F:\\nepalon\\Blips.out")); System.out.println("Recovering Object: "); b1 = (Blip1)in.readObject(); //b2 = (Blip2)in.readObject(); (3) } }
运行结果为: Constructor Object: Blip1 Constructor Blip2 Constructor Saveing Object: Blip1.writeExternal Blip2.writeExternal Recovering Object: Blip1 Constructor Blip1.readexternal 在上面的代码中,class Blip1的default构造函数为public(代码(1)),所以可以完成次第读写的操作。但是class Blip2的default构造函数不为public(代码(2)),所以在进行次第读取(代码(3))操作时,会产生InvalidClassException的异常。 从运行结果可看出,在恢复对象时会调用对象的defqult构造函数。
2.2. Externalizable接口和Serializable接口的区别 1) 通过实现Serializable接口的方法,在保存对象时会把对象中所包含的成员对象也保存下来;而通过实现Externalizable接口的方法,在保存对象时不会保存任何成员对象。 2) 通过实现Serializable接口的方法,在恢复对象时不会调用任何构造函数(包括default构造函数);而通过实现Externalizable接口的方法,在恢复对象时会调用default构造函数。然后再调用readExternal()函数。 2.3. 利用writeExternal()和readExternal()函数来控制成员对象 由于通过实现Externalizable接口的方法,在保存对象时不会保存任何成员对象,但如果要在保存对象的时候要保存对象的成员对象时,我们可以通过这两个函数来实现。
class Blip3 implements Externalizable{ int i; String s1; String s2; public Blip3(){ System.out.println("Blip3 Constructor"); //在default构造函数中只对s2进行初始化 s2 = "default String"; //(1) } public Blip3(String x, int a){ System.out.println("Blip1(String x, int a)"); //在non-default构造函数中初始化i、s1和s2 i = a; s1 = x; s2 = x; } public String toString(){ return "s1 = " + s1 + " , s2 = " + s2 + ", i = " + i; } public void writeExternal(ObjectOutput out) throws IOException{ System.out.println("Blip3.writeExternal"); out.writeObject(s1); out.writeInt(i); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{ System.out.println("Blip2.readExternal"); s1 = (String)in.readObject(); i = in.readInt(); } } public class TestSerialization{ public static void main(String[] args) throws ClassNotFoundException, IOException{ System.out.println("Constructor Object: "); Blip3 b3 = new Blip3("A String", 47); System.out.println(b3); ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("F:\\nepalon\\test\\Blip3.out")); System.out.println("Saveing Object: "); out.writeObject(b3); out.close(); ObjectInputStream in = new ObjectInputStream( new FileInputStream("F:\\nepalon\\test\\Blip3.out")); System.out.println("Recovering Object: "); b3 = (Blip3)in.readObject(); System.out.println(b3); } }
运行结果为: Constructor Object: Blip3(String x, int a) s1 = A String , s2 = A String, i = 47 Saveing Object: Blip3.writeExternal Recovering Object: Blip3 Constructor Blip2.readExternal s1 = A String , s2 = default String, i = 47 //(2) 在上面代码中,在writeExternal()函数中保存了i和s1,在readExternal()函数中恢复了i和s2;而在default构造函数中我们只初始化了s2(代码(1))。从结果(2)处可证明,s2在对象被恢复时在default构造函数中被初始化;而s1和i由于在保存对象时也被保存了,所以能恢复到3. 扩增Serializable接口以实现Externalizable接口的功能 虽然Serializable接口只是个标志封闭器,不具有任何函数,但我们可在实现了该接口的类中扩增writeObject()和readObject()函数,这是Java中最怪异的地方。 3.1. 实现扩增的语法 这两函数的定义为: private void writeObject(ObjectOutputStream stream) throws IOException{; private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException; 3.2. Java的怪异之处 1) 在下面的代码中我们可以看到,Blip3只实现了Serializable接口,而该接口只是个标志接口,所以这两个函数并不是接口的一部分。 2) 这两个函数被声明为private,按理只能在它们所在的类中被调用,但事实却是它们能被ObjectOutputStream和ObjectInputStream对象的writeObject()和readObject()函数调用。 3.3. readObject()和writeObject()函数的使用及其工作过程 3.3.1 工作过程 当调用ObjectOutputStream.writeObject(Object)时,传入的Serializable对象会被检查是否实现自己的writeObject(ObjectOutputStream)。如果有,就会执行扩增的writeObject(ObjectOutputStream)函数。当调用ObjectInputStream.readObject()时的工作过程也一样。 原来的值。
3.3.2 在扩增的writeObject(ObjectOutputStream)中我们可以通过调用defaultWriteobject()函数来执行缺省的writeObject();在扩增的readObject(ObjectInputStream)函数中,我们可以通过调用defaultReadObject()函数来执行缺省的readObject()。在相应的缺省函数中都只对non-transient成员对象进行操作。
import java.io.*; class Blip3 implements Serializable{ String s1; transient String s2; public Blip3(String a, String b){ s1 = "Not Transient: " + a; s2 = "Transient: " + b; } public String toString(){ return "s1 = " + s1 + "\ns2 = " + s2 ; } //函数(1) private void writeObject(ObjectOutputStream stream) throws IOException{ stream.defaultWriteObject(); stream.writeObject(s2); } //函数(2) private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException{ stream.defaultReadObject(); s2 = (String)stream.readObject(); } } public class TestSerialization{ public static void main(String[] args) throws ClassNotFoundException, IOException{ Blip3 b3 = new Blip3("Test1", "Test2"); System.out.println("Before:\n" + b3); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bout); out.writeObject(b3); out.close(); ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream(bout.toByteArray())); System.out.println("Recovering Object: "); b3 = (Blip3)in.readObject(); System.out.println("After:\n" + b3); } }
运行结果为: Before: s1 = Not Transient: Test1 s2 = Transient: Test2 Recovering Object: After: s1 = Not Transient: Test1 s2 = Transient: Test2 在代码的函数(1)中,先保存non-transient成员对象,再保存transient成员对象。在函数(2)中,先恢复non-transient成员对象,再恢复transient成员对象。保存的顺序和恢复的顺序必须相同,否则数据会出错。
4. 关于Serialize的扩充话题 4.1 当多个对象被保存到同一个Stream时,如果这些对象的成员对象中有指向相同的第三对象的reference,那么在恢复时也将指向同一个对象。但不相同的两个Stream中的对象的则不同。
import java.io.*; import java.util.ArrayList; class House implements Serializable {} class Animal implements Serializable{ String name; House house; Animal(String nm, House h){ name = nm; house = h; } public String toString(){ return name + "[" + super.toString() + "], " + house + "\n"; } } public class TestSerialization{ public static void main(String[] args) throws ClassNotFoundException, IOException{ House house = new House(); ArrayList animals = new ArrayList(); animals.add(new Animal("dog", house)); animals.add(new Animal("hamster", house)); animals.add(new Animal("cat", house)); System.out.println("animals: " + animals); //在同一个Stream(Stream1)中保存两次 ByteArrayOutputStream buf1 = new ByteArrayOutputStream(); ObjectOutputStream o1 = new ObjectOutputStream(buf1); o1.writeObject(animals); o1.writeObject(animals); //在另一个Stream(Stream2)中保存 ByteArrayOutputStream buf2 = new ByteArrayOutputStream(); ObjectOutputStream o2 = new ObjectOutputStream(buf2); o2.writeObject(animals); //恢复Stream1中的两个对象 ObjectInputStream in1 = new ObjectInputStream( new ByteArrayInputStream( buf1.toByteArray())); ArrayList animal1 = (ArrayList)in1.readObject(); ArrayList animal2 = (ArrayList)in1.readObject(); //恢复Stream2中的对象 ObjectInputStream in2 = new ObjectInputStream( new ByteArrayInputStream( buf2.toByteArray())); ArrayList animal3 = (ArrayList)in2.readObject(); System.out.println("animal1: " + animal1); System.out.println("animal2: " + animal2); System.out.println("animal3: " + animal3); } }
运行结果为: animals: [dog[Animal@1], House@2 , hamster[Animal@3], House@2 , cat[Animal@4], House@2 ] animal1: [dog[Animal@14], House@15 , hamster[Animal@16], House@15 , cat[Animal@17], House@15 ] animal2: [dog[Animal@14], House@15 , hamster[Animal@16], House@15 , cat[Animal@17], House@15 ] animal3: [dog[Animal@18], House@19 , hamster[Animal@1a], House@19 , cat[Animal@1b], House@19 ] 当在同一个Stream中两次保存animals对象时,它们被恢复后是完全一样的,所以结果中animals1和animals2的对象的地址是一样的。但当把animals保存到另一个Stream中时,当它被恢复后可看到与前两个是不一样的。由结果可知animals1与animals2的信息一样,但这两个对象的信息与animals3的不一样。
发表评论
-
【转】log4j使用完全手册
2010-10-15 11:20 763log4j使用完全手册 见附件 -
【转】Syntax error, parameterized types are only available if source level is 5.0
2010-09-28 14:34 1367用eclpise(或者myeclipse)时候,如果出现以下错 ... -
绿色版的Java Compiler —— jd-gui
2010-05-12 19:23 1045一个很好用的,小巧的Java反编译绿色软件,而且是单文件版的, ... -
java反射机制系列(三)例子分析
2009-05-10 14:30 784上一篇中,通过例子我 ... -
java反射机制(二)例子
2009-05-10 14:25 821下面我以顾客买相机为例来说明Java反射机制的应用。例子中涉及 ... -
java 反射机制系列(一) 初识Java Reflection
2009-05-10 14:22 913Java 反射机制是指Java程序可以在执行期载入,探知,使用 ... -
【转】Java异常处理
2009-05-03 12:25 776你觉得自己是一个Java专 ...
相关推荐
Boost::Serialization是C++库中的一个模块,它提供了一种序列化和反序列化对象的能力。这个库使得能够将复杂的C++对象结构保存到文件、数据库或者网络流中,然后在需要时重新加载,这对于数据持久化、版本控制以及跨...
《深入理解System.Runtime.Serialization.DLL及其在.NET框架中的作用》 在.NET框架中,`System.Runtime.Serialization`命名空间是处理序列化和反序列化的核心组件,而`System.Runtime.Serialization.dll`则是这个...
sirenix.serialization.dll
Boost.Serialization库是C++社区广泛使用的序列化工具,它提供了丰富的功能来处理各种类型的对象,包括智能指针。在C++11及更高版本中,智能指针(如`std::unique_ptr`,`std::shared_ptr`和`std::scoped_ptr`)被...
【Kotlinx.Serialization详解】 Kotlinx.Serialization是一个强大的开源库,专门为Kotlin编程语言提供了跨平台的序列化解决方案。这个库允许开发者将数据对象转换成字节流或JSON等不同格式,反之亦然,这对于数据...
.NET框架中,System.Xml.Serialization 命名空间包含着用来将对象序列化为XML的文本或流的对象。
Fast-serialization,也叫FST(Faster Simple SerializationFast-serialization,也叫FST(Faster Simple Serialization),是一个Java快速对象序列化的开发包。这个库的设计目标是提供比JDK原生序列化更快的速度和...
在.NET中,要实现对象的XML序列化,需要引入`System.Xml.Serialization`命名空间,这提供了必要的类和特性来控制序列化的过程。 首先,确保在项目中添加了对`System.Xml`库的引用,这是.NET Framework的一部分,...
1. **JSON 序列化与反序列化**:`oslo.serialization` 提供了方便的方法将Python对象转换为JSON字符串,以及将JSON字符串解析回Python对象。这在跨语言通信中非常有用,因为JSON是一种广泛接受的标准数据交换格式。 ...
《深入解析System.Runtime.Serialization.dll》 System.Runtime.Serialization.dll是.NET Framework中的一个重要组件,它属于Microsoft的基础类库,主要负责数据序列化和反序列化的功能。数据序列化是将对象的状态...
### Java Streams 和 Serialization 详解 在Java编程语言中,数据的读取与写入操作是通过流(Streams)...无论是进行数据读写还是对象状态的保存与恢复,掌握流和序列化的相关知识都是Java开发者不可或缺的技能之一。
kotlinx-serialization-compiler-plugin.jar
hystrix-serialization-1.5.18.jar
"SerializationTest.zip"文件很显然包含了一些示例或测试,帮助开发者理解如何在C#中处理自定义对象、字典以及复杂对象的序列化和反序列化过程。 序列化是指将对象转换为字节流的过程,这使得对象的状态可以被保存...
本篇文章将深入探讨如何在C#中进行XML的读写操作,以及如何实现XML的序列化和反序列化,这些都是开发过程中的常见任务。 首先,XML读写涉及到两个主要的类:`XmlReader`和`XmlWriter`。`XmlReader`提供了一个高效的...
.net2.0版本的json操作类 ...System.Web.Script.Serialization的json操作类,位于3.0以上的System.Web.Extensions类库中. 本项目是从System.Web.Extensions中剥离出System.Web.Script.Serialization的完整项目
akka-kryo-serialization, 基于Kryo的Akka序列化 akka-kryo-serialization-- Scala 和Akka基于kryo的序列化程序这个库为 Scala 和Akka提供定制的基于kryo的序列化程序。 它可以用于更高效的akka远程处理。它还可以...
数据的序列化和反序列化 Serialization DeSerialization
Kotlin cross-platform / multi-format reflectionless serialization Kotlin serialization consists of a compiler plugin, which automatically produces visitor code for classes, and runtime library, ...