对象序列化

18.12 对象序列化

当你创建对象时,只要你需要,他就会一直存在,但是在程序终止时,无论如何他都不会继续存在。尽管这么做肯定是有意义的。但是仍旧存在某些情况,如果对象能够在程序不运行的情况下仍能存在并保存其信息,那将非常有用。这样,在下次运行程序时,该对象将被重建并且拥有的信息与在程序上次运行时他所有拥有的信息相同。当然,你可以通过信息写入文件或数据库来达到相同的效果,但是在使万物都成为对象的精神中,如果能够将一个对象声明为“持久性”的,并未我们处理掉所有细节,那将会显得十分方便。

Java的对象序列化将那些实现了Serializable接口的对象转换为一个字节序列,并能够在以后将这个字节序列完全回复为原来的对象。这一过程甚至可通过网络进行;这意味着序列化机制能够弥补不同操作系统之间的差异。也就是说,可以在运行Windows系统的计算机上创建一个对象,将其序列化,通过网络将它发送给一台运行Unix系统的计算机,然后在那里准确的重新组装,而却不必担心数据在不同机器上的表示会不同,也不必关心字节的顺序或者其他任何细节。

就其本身来说,对象的序列化是非常有趣的,因为利用他可以实现轻量级持久性。“持久性”意味着一个对象的生存周期并不取决于程序是否正在执行;他可以生存于程序的调用之间。通过将一个序列化对象写入磁盘,然后再重新调用程序时恢复该对象,就能够实现持久性的效果。之所以称其为“轻量级”,是因为不能用某种“persistent”关键字来简单的定义一个对象,并让系统维护其他细节问题。相反,对象必须在程序中显示的序列化和反序列化。如果需要一个更严格的持久性机制,可以考虑像Hibernate之类的工具。

对象序列化的概念加入到语言中是为了支持两种主要特性。一是Java的远程方法调用,它使存活于其他计算机上的对象使用起来就像是存活于本机上一样。当向远程对象发送消息时,需要通过对象序列化来传输参数和返回值。

在者,对于Java Beans来说,对象的序列化也是必须的,使用一个Bean时,一般情况下是在设计阶段对他的状态信息进行配置。这种状态信息必须保存下来,并且在程序启动时进行后期恢复;这种具体工作就是由对象序列化完成的。

只要对象实现了Serializable接口,对象的序列化处理就会非常简单。当序列化的概念被加入到语言中时,许多标准类库都发生了改变,以便具备序列化特性--其中包括所有基本数据类型的封装器,所有容器类以及许多其他的东西。甚至Class对象也可以被序列化。

要序列化一个对象,首先要创建某些OutputStream对象,然后将其封装在一个ObjectOutputStream对象内。这时,只需要调用writeObject()即可将对象序列化,并将其发送给OutputStream。要反向进行该进程,需要将一个InputStream封装在ObjectInputStream内,然后调用readObject()。和往常一样,我们最后获得是一个引用,它指向一个向上转型的Object,所以必须向下转型才能直接设置他们。

对象序列化特别“聪明”的一个地方是它不仅保存了对象的“全景图”,而且能追踪到对象内所包含的所有应用,并保存那些对象;接着又能对对象内包含的每个这样的引用进行追踪;以此类推。这种情况被称为“对象网”,单个对象可与之建立连接,而且他还包含了对象的引用数组以及成员对象。如果必须保持一套自己的对象序列化机制,那么维护那些可追踪到所有链接的代码可能会显得非常麻烦。然而,由于Java的对象序列化似乎找不出什么缺点,所以请尽量不要自己动手,让它用优化的算法自动维护整个对象网。下面这个例子通过对链接的对象生成一个worm对序列化机制进行了测试。每个对象都与worm的下一段链接,同时又与属于不同类的对象引用数组链接:

class Data implements Serializable{
	private int n;
	public Data(int n){this.n=n;}
	public String toString(){return Integer.toString(n);}
}
public class Worm implements Serializable{
	private static Random rand=new Random(47);
	private Data[] d={
			new Data(rand.nextInt(10)),
			new Data(rand.nextInt(10)),
			new Data(rand.nextInt(10))
	};
	private Worm next;
	private char c;
	public Worm(int i,char x){
		System.out.println("Worm constructor:"+i);
		c=x;
		if(--i>0)
			next=new Worm(i,(char)(x+1));
	}
	public Worm(){};
	public String toString(){
		StringBuilder result=new StringBuilder(":");
		result.append(c);
		result.append("(");
		for(Data dat:d)
			result.append(dat);
		result.append(")");
		if(next!=null)
			result.append(next);
		return result.toString();
	}
	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("worm.out"));
		out.writeObject("Worm storage\n");
		out.writeObject(w);
		out.close();
		ObjectInputStream in=new ObjectInputStream(new FileInputStream("worm.out"));
		String s=(String)in.readObject();
		Worm w2=(Worm)in.readObject();
		System.out.println(s+"w2="+w2);
		ByteArrayOutputStream bout=new ByteArrayOutputStream();
		ObjectOutputStream out2=new ObjectOutputStream(bout);
		out2.writeObject("Worm storage\n");
		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内的Data对象数组是用随机数初始化的。每个Worm段都用一个char加以标记。该char是在递归生成链接的Worm列表时自动产生的。要创建一个Worm,必须告诉构造器你所希望的它的长度。在产生下一个引用时,要调用Worm构造器,并将长度减1,以此类推。最后一个next引用则为null,表示已到达Worm的尾部。

以上这些操作都将使得事情变得更加复杂。从而加大了对象序列化的难度。然而,真正的序列化过程却是非常简单的。一旦从另外某个流创建了ObjectOutputStream,writeObject()就会将对象序列化。注意也可以为一个String调用writeObject().也可以用与DataOutputStream相同的方法写入所有基本数据类型。

有两段看起来相似的独立的代码。一个读写的是文件,而另一个读写的是字节数组。可以利用序列化将对象写到任何DataInputStream或者DataOutputStream,甚至包括网络。

从输出中可以看出,被还原的对象确实包含了原对象中的所有链接。

注意在对一个Serializable对象进行还原的过程中,没有调用任何构造器,包括默认的构造器。整个对象都是通过从InputStream中读取数据恢复而来的。

18.12.1 寻找类

那么将一个对象从他的序列化状态中恢复出来,有哪些工作是必须的呢?举个例子来说,如果我们将一个对象序列化,并通过网络将其作为文件传送给另一台计算机,那么另一台计算机上的程序可以只利用该文件内容还原这个对象吗?

回答这个问题的最好方法就是做一个实验。下面这个文件位于本章的目录下:

public class FreezeAlien {
	public static void main(String[] args) throws Exception{
		ObjectOutput out=new ObjectOutputStream(new FileOutputStream("X.file"));
		Alien quellek=new Alien();
		out.writeObject(quellek);
	}
}

这个程序不但能捕获和处理异常,而且将异常抛出main()方法之外,以便通过控制台产生报告。一旦该程序被编译和运行,他就会在c12目录下产生一个名为X.file的文件。以下代码位于一个名为xfiles的子目录下:

package com.tkij.charpter18.section12.xfiles;
import java.io.*;
public class ThawAlien {
	public static void main(String[] args) throws Exception{
		ObjectInputStream in=new ObjectInputStream(new FileInputStream(new File("..","X.file")));
		Object mystery=in.readObject();
		System.out.println(mystery.getClass());
	}

}

打开文件和读取文件mystery对象中的内容都需要Alien的Class对象;而Java虚拟机找不到Alien.class。这样就会得到一个名叫ClassNotFoundException的异常。必须保证Java虚拟机能够找到相关的class文件。

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python对象序列化是指将Python对象转化为字节流的过程,以便在不同的系统之间传输或存储。通过序列化,我们可以将对象保存到磁盘上或通过网络发送给其他计算机。Python提供了pickle模块来实现对象序列化和反序列化。引用中的链接提供了一个关于序列化存储Python对象的示例。 在Python中,变量是对象的引用,可以用多个变量引用同一个对象。因此,通过pickle模块,我们可以轻松地将对象序列化到文件中,并在需要时进行反序列化。引用中提到,Python在处理经过pickle的对象时非常方便。 我们可以使用pickle模块的dump()函数将对象保存到文件中,然后使用load()函数来读取文件并重新创建对象。在引用的代码示例中,我们可以看到定义了一个Student类,其中包含了初始化方法__init__()、保存方法save()和读取方法read(),分别用于初始化对象成员、将对象保存到文件和读取文件的内容。 当我们使用pickle.dump()将Student类的对象s1保存到文件时,可以使用pickle.load()来读取文件并返回一个Student类的对象。在引用的代码示例中,通过调用s1.save()将对象保存到文件,然后通过调用print(s1.read())来读取文件并返回对象。 综上所述,Python对象序列化是将Python对象转化为字节流的过程,可以通过pickle模块的dump()函数将对象保存到文件,再通过load()函数读取文件并返回对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Python中的对象序列化](https://blog.csdn.net/MixJet/article/details/8458101)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Python对象序列化](https://blog.csdn.net/weixin_55696561/article/details/123633077)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值