志在指尖
用双手敲打未来

java深拷贝的实现

在有些业务场景下,咱们需求两个完全相同却互相无关的java方针。比如使用原型模式、多线程编程等。对此,java提供了深仿制的概念。经过深度仿制能够从源方针完美仿制出一个相同却与源方针互相独立的方针方针。这儿的相同是指两个方针的状况和动作相同,互相独立是指改变其中一个方针的状况不会影响到别的一个方针。完成深仿制常用的完成办法有2种:Serializable,Cloneable。
Serializable办法便是经过java方针的序列化和反序列化的操作完成方针仿制的一种比较常见的办法。原本java方针们都待在虚拟机堆中,经过序列化,将源方针的信息以别的一种形式存放在了堆外。这时源方针的信息就存在了2份,一份在堆内,一份在堆外。然后将堆外的这份信息经过反序列化的办法再放回到堆中,就创建了一个新的方针,也便是方针方针。java
–Serializable代码
仿制代码
publicstaticObjectcloneObjBySerialization(Serializablesrc)
{
Objectdest=null;try{
ByteArrayOutputStreambos=null;
ObjectOutputStreamoos=null;try{
bos=newByteArrayOutputStream();
oos=newObjectOutputStream(bos);
oos.writeObject(src);
oos.flush();
}finally{
oos.close();
}byte[]bytes=bos.toByteArray();
ObjectInputStreamois=null;try{
ois=newObjectInputStream(newByteArrayInputStream(bytes));
dest=ois.readObject();
}finally{
ois.close();
}
}catch(Exceptione)
{
e.printStackTrace();//克隆失败}returndest;
}
仿制代码
源方针类型及其成员方针类型需求完成Serializable接口,一个都不能少。
仿制代码
importjava.io.Serializable;publicclassBattleShipimplementsSerializable
{Stringname;
ClonePilotpilot;
BattleShip(Stringname,ClonePilotpilot)
{this.name=name;this.pilot=pilot;
}
}//ClonePilot类型完成了Cloneable接口,不过这对经过Serializable办法仿制方针没有影响publicclassClonePilotimplementsSerializable,Cloneable
{
Stringname;
Stringsex;
ClonePilot(Stringname,Stringsex)
{this.name=name;this.sex=sex;
}publicClonePilotclone()
{try{
ClonePilotdest=(ClonePilot)super.clone();returndest;
}catch(Exceptione)
{
e.printStackTrace();
}returnnull;
}
}
仿制代码
最后,履行测验代码,查看成果。
仿制代码
publicstaticvoidmain(String[]args)
{
BattleShipbs=newBattleShip(“Dominix”,newClonePilot(“Alex”,”male”));
System.out.println(bs);
System.out.println(bs.name+””+bs.pilot.name);
BattleShipcloneBs=(BattleShip)CloneObjUtils.cloneObjBySerialization(bs);
System.out.println(cloneBs);
System.out.println(cloneBs.name+””+cloneBs.pilot.name);
}
console–output–
cloneObject.BattleShip@154617c
DominixAlex
cloneObject.BattleShip@cbcfc0
DominixAlex
cloneObject.ClonePilot@a987ac
cloneObject.ClonePilot@1184fc6
仿制代码
从控制台的输出能够看到,两个不同的BattleShip方针,各自引证着不同的Clonepilot方针。String作为不可变类,这儿能够作为根本类型处理。该有的数据都有,两个BattleShip方针也没有引证同一个成员方针的状况。表明深仿制成功了。
留意序列化会忽略transient润饰的变量。所以这种办法不会仿制transient润饰的变量。
别的一种办法是Cloneable,中心是Object类的native办法clone()。经过调用clone办法,能够创建出一个当时方针的克隆体,但需求留意的是,这个办法不支持深仿制。如果方针的成员变量是根底类型,那妥妥的没问题。但是对于自定义类型的变量或许调集(调集我还没测验过)、数组,就有问题了。你会发现源方针和方针方针的自定义类型成员变量是同一个方针,也便是浅仿制,浅仿制便是对方针引证(地址)的仿制。这样的话源方针和方针方针就不是互相独立,而是羁绊不休了。为了补偿clone办法的这个不足。需求咱们自己去处理非根本类型成员变量的深仿制。
–Cloneable代码
仿制代码
publicclassCruiserimplementsCloneable
{
Stringname;
ClonePilotpilot;
Cruiser(Stringname,ClonePilotpilot)
{this.name=name;this.pilot=pilot;
}//Object.clone办法是protected润饰的,无法在外部调用。所以这儿需求重载clone办法,改为public润饰,而且处理成员变量浅仿制的问题。publicCruiserclone()
{try{
Cruiserdest=(Cruiser)super.clone();
dest.pilot=this.pilot.clone();returndest;
}catch(Exceptione)
{
e.printStackTrace();
}returnnull;
}
}
仿制代码
仿制代码
publicclassClonePilotimplementsSerializable,Cloneable
{
Stringname;
Stringsex;
ClonePilot(Stringname,Stringsex)
{this.name=name;this.sex=sex;
}//由于一切成员变量都是根本类型,所以只需求调用Object.clone()即可publicClonePilotclone()
{try{
ClonePilotdest=(ClonePilot)super.clone();returndest;
}catch(Exceptione)
{
e.printStackTrace();
}returnnull;
}
}
仿制代码
下面测验一下
仿制代码
publicstaticvoidmain(String[]args)
{
Cruisercruiser=newCruiser(“VNI”,newClonePilot(“Alex”,”male”));
System.out.println(cruiser);
CruisercloneCruiser=cruiser.clone();
System.out.println(cloneCruiser);
System.out.println(cruiser.pilot);
System.out.println(cloneCruiser.pilot);
System.out.println(cruiser.pilot.name);
System.out.println(cloneCruiser.pilot.name);
}
仿制代码
履行成果如下:
仿制代码
cloneObject.Cruiser@1eba861
cloneObject.Cruiser@1480cf9
cloneObject.ClonePilot@1496d9f
cloneObject.ClonePilot@3279cf
Alex
Alex
仿制代码
同样,从控制台的输出能够看到,两个不同的Cruiser方针,各自引证着不同的Clonepilot方针。该有的数据都有,两个Cruiser方针也没有引证同一个成员方针的状况。表明深仿制成功了。

未经允许不得转载:IT技术网站 » java深拷贝的实现
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载