论坛首页 Java企业应用论坛

Java序列化机制的基本知识

浏览 33695 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2005-07-18  
robbin 写道


public class Item implements Serializable {
    //  所有的属性和getter/setter方法同上,省略
    public Bid placeBid(User bidder, MonetaryAmount bidAmount,
                        Bid currentMaxBid, Bid currentMinBid)
    	throws BusinessException {
    
    	// Check highest bid (can also be a different Strategy (pattern))
    	if (currentMaxBid != null && currentMaxBid.getAmount().compareTo(bidAmount) > 0) {
    		throw new BusinessException("Bid too low.");
    	}
    
    	// Auction is active
    	if ( !state.equals(ItemState.ACTIVE) )
    		throw new BusinessException("Auction is not active yet.");
    
    	// Auction still valid
    	if ( this.getEndDate().before( new Date() ) )
    		throw new BusinessException("Can't place new bid, auction already ended.");
    
    	// Create new Bid
    	Bid newBid = new Bid(bidAmount, this, bidder);
    
    	// Place bid for this Item
    	this.getBids.add(newBid);  // 请注意这一句,透明的进行了持久化,但是不能在这里调用ItemDao,Item不能对ItemDao产生依赖!
    
    	return newBid;
    }
}




你这里的domain object既然实现了Serializable 接口,说明domain object是需要被序列化的,如果在序列化的时候不但序列化了一堆属性,还要序列化一大堆少用到的方法,效率是否太底?对于你这里的domain object,我们80%的时间用到其中80%的属性,20%的时间用到其中20%的方法。要知道序列化是非常耗费资源的,并且序列化出来的对象与序列化前的大小不是一个数量级的。不然怎么会出现value object模式,怎么会有贫血模型的产生!
   发表时间:2005-07-18  
引用
如果在序列化的时候不但序列化了一堆属性,还要序列化一大堆少用到的方法,效率是否太底


这是什么奇谈怪论? 请问什么叫做序列化方法,请问Java如何序列化方法?
0 请登录后投票
   发表时间:2005-07-18  
  我指的是在一个要序列化的对象中既包含了对象的属性又包含了对象的业务逻辑方法,对象的序列化和反序列化的过程中就必须对这些属性和方法进行序列化和反序列化。这也是为什么在网络传输环境下为什么要把方法和属性分离的一个原因,因为大多数情况下我们需要传输的仅仅是数据(属性),而不是怎样处理数据的方法。贫血模型的产生不无道理。当然,大家可以说现在的硬件及网络速率已经大大提高,这些资源消耗无足轻重。但想想看贫血模型产生时所处的环境,当时的硬件和网络传输水平。也应该思考一下,资源对于系统就真的那么不重要了吗,软件不行硬件顶上?
1 请登录后投票
   发表时间:2005-07-18  
robbin 写道


这是什么奇谈怪论? 请问什么叫做序列化方法,请问Java如何序列化方法?

众所周知,对象要在网络上传输就必须被序列化,或者说串行化,转化成流式结构。java怎么序列化domain object中的属性和get/set方法,就怎么序列化其中的业务方法.
0 请登录后投票
   发表时间:2005-07-18  
序列化是将对象转换为容易传输的格式的过程。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。在另一端,反序列化将从该流重新构造对象。

这里要明确一点:序列化不是序列化某个属性或方法,而是序列化对象(当然,对象中的属性和方法可以在定义时加上transient或static关键字以确保不被序列化)。

这里贴一个序列化的步骤,是。NET的,JAVA应该类似。我想我自己说的肯定没它说的好。
序列化过程的步骤
在格式化程序上调用 Serialize 方法时,对象序列化按照以下规则进行:

检查格式化程序是否有代理选取器。如果有,检查代理选取器是否处理指定类型的对象。如果选取器处理此对象类型,将在代理选取器上调用 ISerializable.GetObjectData。
如果没有代理选取器或有却不处理此类型,将检查是否使用 Serializable 属性对对象进行标记。如果未标记,将会引发 SerializationException。
如果对象已被正确标记,将检查对象是否实现了 ISerializable。如果已实现,将在对象上调用 GetObjectData。
如果对象未实现 Serializable,将使用默认的序列化策略,对所有未标记为 NonSerialized 的字段都进行序列化。


不好意思,发的快没你转的快,把我那边的帖子删掉吧。
0 请登录后投票
   发表时间:2005-07-18  
这里有谁真的在网络上传输domain object,不妨站出来让大家瞻仰一下:D
0 请登录后投票
   发表时间:2005-07-18  
redlly,我不知道你所谓的Java可以对方法进行序列化是如何进行序列化的,我猜测是你自己凭空想像出来的,因为Java的序列化机制只序列化对象的属性值,而不会去序列化什么所谓的方法。

其实这个问题简单思考一下就可以搞清楚,方法是不带状态的,就是一些指令,指令是不需要序列化的,只要你的JVM classloader可以load到这个类,那么类方法指令自然就可以获得。序列化真正需要保存的只是对象属性的值,和对象的类型。

这些知识找一本Java基础编程的书,或者Java手册就可以查到,我以为是不应该犯这种基本概念错误的。

我们可以做一个简单的小试验,来证实一下:

package com.javaeye;

import java.io.Serializable;

public class DomainObject  implements Serializable {

	private String name;
	
	private int age ;

	public int getAge(); {
		return age;
	}

	public void setAge(int age); {
		this.age = age;
	}

	public String getName(); {
		return name;
	}

	public void setName(String name); {
		this.name = name;
	}
	
	
}



package com.javaeye;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class Main {

	public static void main(String[] args); throws Exception {
		DomainObject obj = new DomainObject();;
		obj.setAge(29);;
		obj.setName("fankai");;
		FileOutputStream fos = new FileOutputStream("DomainObject");;
		ObjectOutputStream oos = new ObjectOutputStream(fos);;
		oos.writeObject(obj);;
		oos.close();;
		fos.close();;
	}

}



DomainObject是我们准备序列化的类,在Main里面,我们new一个DomainObject的对象,然后赋值,最后把该对象序列化到一个硬盘文件中。

然后使用一种支持二进制编辑器,例如UltraEdit打开这个文件,看看Java都对DomainObject序列化了哪些信息,你就什么都明白了。

为了更方便观察,我使用Linux下面的strings去提取文本信息,输出为:

robbin@linux:~> strings DomainObject
com.javaeye.DomainObject
ageL
namet
Ljava/lang/String;xp
fankai

这些信息很直观的告诉我们序列化都保存了些什么内容:
1)对象的类型
2)对象属性的类型
3)对象属性的值

并没有什么方法签名的信息,更不要说什么序列化方法了。

然后我们再做一个试验,给DomainObject增加两个方法:
package com.javaeye;

import java.io.Serializable;

public class DomainObject  implements Serializable {

	private String name;
	
	private int age ;

	public int getAge(); {
		return age;
	}

	public void setAge(int age); {
		this.age = age;
	}

	public String getName(); {
		return name;
	}

	public void setName(String name); {
		this.name = name;
	}
	
	public String toString(); {
		return "This is a serializable test!";
	}
	
	public void doSomeWork(); {
		System.out.println("hello");;
	}
}


我们增加了toString方法和doSomeWork方法,按照你的理论,如果序列化方法的话,产生的文件体积必然增大。记录一下文件体积,92Byte,好了,删除,运行程序,生成了新的文件,看一下体积,还是92Byte!

拿到Linux下面再提取一下字符串:

robbin@linux:~> strings DomainObject
com.javaeye.DomainObject
ageL
namet
Ljava/lang/String;xp
fankai

完全一模一样!

然后我们再做第三个试验,这次把DomainObject的两个属性以及相关方法删除掉:
package com.javaeye;

import java.io.Serializable;

public class DomainObject  implements Serializable {

	public String toString(); {
		return "This is a serializable test!";
	}
	
	public void doSomeWork(); {
		System.out.println("hello");;
	}
}


修改Main类如下:

package com.javaeye;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class Main {

	public static void main(String[] args); throws Exception {
		DomainObject obj = new DomainObject();;

		FileOutputStream fos = new FileOutputStream("DomainObject");;
		ObjectOutputStream oos = new ObjectOutputStream(fos);;
		oos.writeObject(obj);;
		oos.close();;
		fos.close();;
	}

}


按照你的理论,如果序列化方法的话,我们必然应该在文件里面发现方法的签名信息,甚至方法里面包含的字符串,好了,再运行一遍,然后打开看一下吧!文件现在体积变成了45Byte,拿到Linux下面提取一下信息:

robbin@linux:~> strings DomainObject
com.javaeye.DomainObject

只有对象的类型信息,再无其它东西了!

请记住序列化机制只保存对象的类型信息,属性的类型信息和属性值,和方法没有什么关系,你就是给这个类增加10000个方法,序列化内容也不会增加任何东西,不要想当然的臆测自己不了解的知识,动手去做!
0 请登录后投票
   发表时间:2005-07-18  
java好像不序列化方法吧。。。

为什么要序列化方法,难道是从里面构造一个类出来?
0 请登录后投票
   发表时间:2005-07-18  
redlly 写道
序列化是将对象转换为容易传输的格式的过程。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。在另一端,反序列化将从该流重新构造对象。

这里要明确一点:序列化不是序列化某个属性或方法,而是序列化对象(当然,对象中的属性和方法可以在定义时加上transient或static关键字以确保不被序列化)。

这里贴一个序列化的步骤,是。NET的,JAVA应该类似。我想我自己说的肯定没它说的好。
序列化过程的步骤
在格式化程序上调用 Serialize 方法时,对象序列化按照以下规则进行:

检查格式化程序是否有代理选取器。如果有,检查代理选取器是否处理指定类型的对象。如果选取器处理此对象类型,将在代理选取器上调用 ISerializable.GetObjectData。
如果没有代理选取器或有却不处理此类型,将检查是否使用 Serializable 属性对对象进行标记。如果未标记,将会引发 SerializationException。
如果对象已被正确标记,将检查对象是否实现了 ISerializable。如果已实现,将在对象上调用 GetObjectData。
如果对象未实现 Serializable,将使用默认的序列化策略,对所有未标记为 NonSerialized 的字段都进行序列化。


不好意思,发的快没你转的快,把我那边的帖子删掉吧。


你贴的这个dotnet的序列化机制已经很明确的说明了只序列化属性,而不序列化方法了。
0 请登录后投票
   发表时间:2005-07-18  
承认错误。robbin分析得很深刻,应该动手亲自验证。
不过在这里也证实了我的说法部分还是正确,序列化还是很占资源的后的对象体积这里达到92K,数据不过是:
引用
obj.setAge(29);
                obj.setName("fankai");

而把这一系列帖子都保存下来作为文本文件也不过10来K。
所以不宜构造巨大的dto,因为其中很多属性可能根本用不着,而可以通过粒度相对较小的dto构造相对复杂的domain object.
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics