|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
轮性能微软曾做过一个例子,就是同一个项目用java和.net网页编程来作,结果开发周期,.net网页编程是java的一半,性能java是.net网页编程的十分之一,代码量java是.net网页编程的三倍。呵呵,这说明了什么,.net网页编程的全方位比java好。但是有的人说.net网页编程不能跨平台,这个问题我和我同学曾讨论过,都认为微软的.net网页编程很可能早都可以跨平台了,但是微软为了保护他们的操作系统,所以才没有推出跨平台的.net网页编程,只是推出了跨语言的.net网页编程,
正如人人看到的那样,默许的序列化机制其实不难利用。但是,倘使有特别请求又该怎样办呢?我们大概有特别的平安成绩,不但愿对象的某一部分序列化;大概某一个子对象完整不用序列化,由于对象恢复今后,那一部分必要从头创立。
此时,经由过程完成Externalizable接口,用它取代Serializable接口,即可把持序列化的详细历程。这个Externalizable接口扩大了Serializable,并增加了两个办法:writeExternal()和readExternal()。在序列化和从头拆卸的过程当中,会主动挪用这两个办法,以便我们实行一些特别操纵。
上面这个例子展现了Externalizable接口办法的复杂使用。注重Blip1和Blip2几近完整分歧,除极巨大的不同(本人研讨一下代码,看看是不是能发明):- //:Blips.java
- //SimpleuseofExternalizable&apitfall
- importjava.io.*;
- importjava.util.*;
- classBlip1implementsExternalizable{
- publicBlip1(){
- System.out.println("Blip1Constructor");
- }
- publicvoidwriteExternal(ObjectOutputout)
- throwsIOException{
- System.out.println("Blip1.writeExternal");
- }
- publicvoidreadExternal(ObjectInputin)
- throwsIOException,ClassNotFoundException{
- System.out.println("Blip1.readExternal");
- }
- }
- classBlip2implementsExternalizable{
- Blip2(){
- System.out.println("Blip2Constructor");
- }
- publicvoidwriteExternal(ObjectOutputout)
- throwsIOException{
- System.out.println("Blip2.writeExternal");
- }
- publicvoidreadExternal(ObjectInputin)
- throwsIOException,ClassNotFoundException{
- System.out.println("Blip2.readExternal");
- }
- }
- publicclassBlips{
- publicstaticvoidmain(String[]args){
- System.out.println("Constructingobjects:");
- Blip1b1=newBlip1();
- Blip2b2=newBlip2();
- try{
- ObjectOutputStreamo=
- newObjectOutputStream(
- newFileOutputStream("Blips.out"));
- System.out.println("Savingobjects:");
- o.writeObject(b1);
- o.writeObject(b2);
- o.close();
- //Nowgetthemback:
- ObjectInputStreamin=
- newObjectInputStream(
- newFileInputStream("Blips.out"));
- System.out.println("Recoveringb1:");
- b1=(Blip1)in.readObject();
- //OOPS!Throwsanexception:
- //!System.out.println("Recoveringb2:");
- //!b2=(Blip2)in.readObject();
- }catch(Exceptione){
- e.printStackTrace();
- }
- }
- }///:~
复制代码
该程序输入以下:- Constructingobjects:
- Blip1Constructor
- Blip2Constructor
- Savingobjects:
- Blip1.writeExternal
- Blip2.writeExternal
- Recoveringb1:
- Blip1Constructor
- Blip1.readExternal
复制代码
未恢复Blip2对象的缘故原由是那样做会招致一个背例。你找出了Blip1和Blip2之间的区分吗?Blip1的构建器是“大众的”(public),Blip2的构建器则否则,如许便会在恢复时形成背例。尝尝将Blip2的构建器属性酿成“public”,然后删除//!正文标志,看看是不是能失掉准确的了局。
恢复b1后,会挪用Blip1默许构建器。这与恢复一个Serializable(可序列化)对象分歧。在后者的情形下,对象完整以它保留上去的二进制位为基本恢复,不存在构建器挪用。而对一个Externalizable对象,一切一般的默许构建举动城市产生(包含在字段界说时的初始化),并且会挪用readExternal()。必需注重这一现实——出格注重一切默许的构建举动城市举行——不然很难在本人的Externalizable对象中发生准确的举动。
上面这个例子展现了保留和恢复一个Externalizable对象必需做的全体事变:- //:Blip3.java
- //Reconstructinganexternalizableobject
- importjava.io.*;
- importjava.util.*;
- classBlip3implementsExternalizable{
- inti;
- Strings;//Noinitialization
- publicBlip3(){
- System.out.println("Blip3Constructor");
- //s,inotinitialized
- }
- publicBlip3(Stringx,inta){
- System.out.println("Blip3(Stringx,inta)");
- s=x;
- i=a;
- //s&iinitializedonlyinnon-default
- //constructor.
- }
- publicStringtoString(){returns+i;}
- publicvoidwriteExternal(ObjectOutputout)
- throwsIOException{
- System.out.println("Blip3.writeExternal");
- //Youmustdothis:
- out.writeObject(s);out.writeInt(i);
- }
- publicvoidreadExternal(ObjectInputin)
- throwsIOException,ClassNotFoundException{
- System.out.println("Blip3.readExternal");
- //Youmustdothis:
- s=(String)in.readObject();
- i=in.readInt();
- }
- publicstaticvoidmain(String[]args){
- System.out.println("Constructingobjects:");
- Blip3b3=newBlip3("AString",47);
- System.out.println(b3.toString());
- try{
- ObjectOutputStreamo=
- newObjectOutputStream(
- newFileOutputStream("Blip3.out"));
- System.out.println("Savingobject:");
- o.writeObject(b3);
- o.close();
- //Nowgetitback:
- ObjectInputStreamin=
- newObjectInputStream(
- newFileInputStream("Blip3.out"));
- System.out.println("Recoveringb3:");
- b3=(Blip3)in.readObject();
- System.out.println(b3.toString());
- }catch(Exceptione){
- e.printStackTrace();
- }
- }
- }///:~
复制代码
个中,字段s和i只在第二个构建器中初始化,不关默许构建器的事。这意味着假设不在readExternal中初始化s和i,它们就会成为null(由于在对象创立的第一步中已将对象的存储空间扫除为1)。若正文失落跟从于“Youmustdothis”前面的两行代码,并运转程序,就会发明当对象恢复今后,s是null,而i是零。
若从一个Externalizable对象承继,一般必要挪用writeExternal()和readExternal()的基本类版本,以便准确地保留和恢复基本类组件。
以是为了让统统一般运作起来,万万不成仅在writeExternal()办法实行时代写进对象的主要数据(没有默许的举动可用来为一个Externalizable对象写进一切成员对象)的,而是必需在readExternal()办法中也恢复那些数据。初度操纵时大概会有些不习气,由于Externalizable对象的默许构建举动使其看起来仿佛正在举行某种存储与恢复操纵。但真相并不是云云。
1.transient(一时)关头字
把持序列化历程时,大概有一个特定的子对象不肯让Java的序列化机制主动保留与恢复。一样平常地,若谁人子对象包括了不想序列化的敏感信息(如暗码),就会晤临这类情形。即便那种信息在对象中具有“private”(公有)属性,但一旦经序列化处置,人们就能够经由过程读取一个文件,大概拦阻收集传输失掉它。
为避免对象的敏感部分被序列化,一个举措是将本人的类完成为Externalizable,就象后面展现的那样。如许一来,没有任何工具能够主动序列化,只能在writeExternal()明白序列化那些必要的部分。
但是,若操纵的是一个Serializable对象,一切序列化操纵城市主动举行。为办理这个成绩,能够用transient(一时)逐一字段地封闭序列化,它的意义是“不要贫苦你(指主动机制)保留或恢复它了——我会本人处置的”。
比方,假定一个Login对象包括了与一个特定的登录会话有关的信息。校验登录的正当性时,一样平常都想将数据保留上去,但不包含暗码。为做到这一点,最复杂的举措是完成Serializable,并将password字段设为transient。上面是详细的代码:- //:Logon.java
- //Demonstratesthe"transient"keyword
- importjava.io.*;
- importjava.util.*;
- classLogonimplementsSerializable{
- privateDatedate=newDate();
- privateStringusername;
- privatetransientStringpassword;
- Logon(Stringname,Stringpwd){
- username=name;
- password=pwd;
- }
- publicStringtoString(){
- Stringpwd=
- (password==null)?"(n/a)":password;
- return"logoninfo:
- "+
- "username:"+username+
- "
- date:"+date.toString()+
- "
- password:"+pwd;
- }
- publicstaticvoidmain(String[]args){
- Logona=newLogon("Hulk","myLittlePony");
- System.out.println("logona="+a);
- try{
- ObjectOutputStreamo=
- newObjectOutputStream(
- newFileOutputStream("Logon.out"));
- o.writeObject(a);
- o.close();
- //Delay:
- intseconds=5;
- longt=System.currentTimeMillis()
- +seconds*1000;
- while(System.currentTimeMillis()<t)
- ;
- //Nowgetthemback:
- ObjectInputStreamin=
- newObjectInputStream(
- newFileInputStream("Logon.out"));
- System.out.println(
- "Recoveringobjectat"+newDate());
- a=(Logon)in.readObject();
- System.out.println("logona="+a);
- }catch(Exceptione){
- e.printStackTrace();
- }
- }
- }///:~
复制代码
能够看到,个中的date和username字段坚持原始形态(未设成transient),以是会主动序列化。但是,password被设为transient,以是不会主动保留到磁盘;别的,主动序列化机制也不会作恢复它的实验。输入以下:- logona=logoninfo:
- username:Hulk
- date:SunMar2318:25:53PST1997
- password:myLittlePony
- RecoveringobjectatSunMar2318:25:59PST1997
- logona=logoninfo:
- username:Hulk
- date:SunMar2318:25:53PST1997
- password:(n/a)
复制代码
一旦对象恢复成本来的模样,password字段就会酿成null。注重必需用toString()反省password是不是为null,由于若用过载的“+”运算符来拆卸一个String对象,并且谁人运算符碰到一个null句柄,就会形成一个名为NullPointerException的背例(新版Java大概会供应制止这个成绩的代码)。
我们也发明date字段被保留到磁盘,并从磁盘恢复,没有从头天生。
因为Externalizable对象默许时不保留它的任何字段,以是transient关头字只能陪伴Serializable利用。
2.Externalizable的替换办法
若不是出格在乎要完成Externalizable接口,另有另外一种办法可供选用。我们能够完成Serializable接口,并增加(注重是“增加”,而非“掩盖”大概“完成”)名为writeObject()和readObject()的办法。一旦对象被序列化大概从头拆卸,就会分离挪用那两个办法。也就是说,只需供应了这两个办法,就会优先利用它们,而不思索默许的序列化机制。
这些办法必需含有以下正确的署名:- privatevoid
- writeObject(ObjectOutputStreamstream)
- throwsIOException;
- privatevoid
- readObject(ObjectInputStreamstream)
- throwsIOException,ClassNotFoundException
复制代码
从计划的角度动身,情形变得有些空中楼阁。起首,人人大概以为这些办法不属于基本类大概Serializable接口的一部分,它们应当在本人的接口中失掉界说。但请注重它们被界说成“private”,这意味着它们只能由这个类的其他成员挪用。但是,我们实践其实不从这个类的其他成员中挪用它们,而是由ObjectOutputStream和ObjectInputStream的writeObject()及readObject()办法来挪用我们对象的writeObject()和readObject()办法(注重我在这里用了很年夜的克制力来制止利用不异的办法名——由于怕搅浑)。人人大概奇异ObjectOutputStream和ObjectInputStream怎样有权会见我们的类的private办法——只能以为这是序列化机制玩的一个幻术。
在任何情形下,接口中的界说的任何工具城市主动具有public属性,以是倘使writeObject()和readObject()必需为private,那末它们不克不及成为接口(interface)的一部分。但因为我们正确地加上了署名,以是终极的效果实践与完成一个接口是不异的。
看起来仿佛我们挪用ObjectOutputStream.writeObject()的时分,我们传送给它的Serializable对象仿佛会被反省是不是完成了本人的writeObject()。若谜底是一定的是,便会跳过惯例的序列化历程,并挪用writeObject()。readObject()也会碰到一样的情形。
还存在另外一个成绩。在我们的writeObject()外部,能够挪用defaultWriteObject(),从而决意接纳默许的writeObject()举动。相似地,在readObject()外部,能够挪用defaultReadObject()。上面这个复杂的例子演示了怎样对一个Serializable对象的存储与恢复举行把持:- //:SerialCtl.java
- //Controllingserializationbyaddingyourown
- //writeObject()andreadObject()methods.
- importjava.io.*;
- publicclassSerialCtlimplementsSerializable{
- Stringa;
- transientStringb;
- publicSerialCtl(Stringaa,Stringbb){
- a="NotTransient:"+aa;
- b="Transient:"+bb;
- }
- publicStringtoString(){
- returna+"
- "+b;
- }
- privatevoid
- writeObject(ObjectOutputStreamstream)
- throwsIOException{
- stream.defaultWriteObject();
- stream.writeObject(b);
- }
- privatevoid
- readObject(ObjectInputStreamstream)
- throwsIOException,ClassNotFoundException{
- stream.defaultReadObject();
- b=(String)stream.readObject();
- }
- publicstaticvoidmain(String[]args){
- SerialCtlsc=
- newSerialCtl("Test1","Test2");
- System.out.println("Before:
- "+sc);
- ByteArrayOutputStreambuf=
- newByteArrayOutputStream();
- try{
- ObjectOutputStreamo=
- newObjectOutputStream(buf);
- o.writeObject(sc);
- //Nowgetitback:
- ObjectInputStreamin=
- newObjectInputStream(
- newByteArrayInputStream(
- buf.toByteArray()));
- SerialCtlsc2=(SerialCtl)in.readObject();
- System.out.println("After:
- "+sc2);
- }catch(Exceptione){
- e.printStackTrace();
- }
- }
- }///:~
复制代码
在这个例子中,一个String坚持原始形态,其他设为transient(一时),以便证实非一时字段会被defaultWriteObject()办法主动保留,而transient字段必需在程序中明白保留和恢复。字段是在构建器外部初始化的,而不是在界说的时分,这证实了它们不会在从头拆卸的时分被某些主动化机制初始化。
若筹办经由过程默许机制写进对象的非transient部分,那末必需挪用defaultWriteObject(),令其作为writeObject()中的第一个操纵;并挪用defaultReadObject(),令其作为readObject()的第一个操纵。这些都是不罕见的挪用办法。举个例子来讲,当我们为一个ObjectOutputStream挪用defaultWriteObject()的时分,并且没无为其传送参数,就必要接纳这类操纵,使其晓得对象的句柄和怎样写进一切非transient的部分。这类做法十分方便。
transient对象的存储与恢复接纳了我们更熟习的代码。如今思索一下会产生一些甚么事变。在main()中会创立一个SerialCtl对象,随后会序列化到一个ObjectOutputStream里(注重这类情形下利用的是一个缓冲区,而非文件——与ObjectOutputStream完整分歧)。正式的序列化操纵是鄙人面这行代码里产生的:
o.writeObject(sc);
个中,writeObject()办法必需核对sc,判别它是不是有本人的writeObject()办法(不是反省它的接口——它基本就没有,也不是反省类的范例,而是使用反射办法实践搜刮办法)。若谜底是一定的,就利用谁人办法。相似的情形也会在readObject()上产生。也许这是办理成绩独一实践的办法,但的确显得有些乖僻。
3.版本成绩
偶然候大概想改动一个可序列化的类的版本(好比原始类的对象大概保留在数据库中)。只管这类做法失掉了撑持,但一样平常只应在十分特别的情形下才用它。别的,它请求操纵者对面前的道理有一个对照深的熟悉,而我们在这里还不想到达这类深度。JDK1.1的HTML文档对这一主题举行了十分周全的叙述(可从Sun公司下载,但大概同样成了Java开辟包联机文档的一部分)。
J2ME在手机游戏开发的作用也是无用质疑的。至于桌面程序,可能有人说java不行,界面不好看,但是请看看net网页编程Beans和Eclipse吧,他们都是利用java开发的,而他们的界面是多么的华丽,所以界面决不是java的缺点。还有一个不得不提的优点就是大多java人员都挂在嘴边的java的跨平台性,目前这确实也是java优点之一。 |
|