在JAVA中克隆一个对象常见的有三种形式
1.通过自己写一个克隆方法里面 new 一个同样的对象来进行 get、set 依次赋值实现深度克隆(很繁琐且易出错);
2.通过实现 Cloneable 接口并重写 Object 类的 clone() 方法(分为深浅两种方式);
3.通过实现 Serializable 接口并用对象的序列化和反序列化来实现真正的深度克隆;
第一种方法并没有什么卵用
Cloneable 接口实现浅克隆
public class People implements Cloneable {
private String name = "ilt";
private Hand hand = new Hand();
public Hand getHand() {
return hand;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
People p1 = new People();
People p2 = (People) p1.clone();
System.out.println("第一个对象的hash值:"+p1.hashCode());
System.out.println("第二个对象的hash值:"+p2.hashCode());
System.out.println("分割线-----------");
System.out.println("p1中的hand对象的hash值:"+p1.getHand().hashCode());
System.out.println("p2中的hand对象的hash值:"+p2.getHand().hashCode());
}
}
class Hand implements Cloneable {
}
上面代码输出的结果如下,根据hash值相等能确定两个对象是否相等的原则,发现p1和p2不等,但p1中的hand对象与p2中的hand对象是相等的。Cloneable 接口实现克隆是先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容,对基本数据类型就是值复制,而对非基本类型变量保存的仅仅是对象的引用,所以会导致 clone 后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。
第一个对象的hash值:1408448235
第二个对象的hash值:77244764
分割线-----------
p1中的hand对象的hash值:1172625760
p2中的hand对象的hash值:1172625760
Cloneable 接口实现深克隆
在浅度克隆的基础上对于要克隆对象中的非基本数据类型的属性对应的类也实现克隆,这样对于非基本数据类型的属性复制的不是一份引用。
public class People implements Cloneable {
private String name = "ilt";
private Hand hand = new Hand();
public Hand getHand() {
return hand;
}
public void setHand(Hand hand) {
this.hand = hand;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
People p2 = (People) super.clone();
p2.setHand((Hand) hand.clone());
return p2;
}
public static void main(String[] args) throws CloneNotSupportedException {
People p1 = new People();
People p2 = (People) p1.clone();
System.out.println("第一个对象的hash值:" + p1.hashCode());
System.out.println("第二个对象的hash值:" + p2.hashCode());
System.out.println("分割线-----------");
System.out.println("p1中的hand对象的hash值:" + p1.getHand().hashCode());
System.out.println("p2中的hand对象的hash值:" + p2.getHand().hashCode());
}
}
class Hand implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
结果如下,证明已经进行深克隆
第一个对象的hash值:1172625760
第二个对象的hash值:863719801
分割线-----------
p1中的hand对象的hash值:1696725334
p2中的hand对象的hash值:427340025
序列化与反序列化实现深克隆
对象序列化操作可以将对象的状态转换成字节流传输或者存储再生,我们可以借用这一特点实现对象的深度克隆,特别是当我们的对象嵌套非常复杂且想实现深度克隆时如果使用序列化方式会大大减少代码量。
public class TestClone implements Serializable{
private static final long serialVersionUID = 1L;
public String name = "ilt";
public static void main(String[] args) throws Exception {
TestClone t1 = new TestClone();
byte[] b = ObjectUtil.objectToBytes(t1);//序列化
TestClone t2 = (TestClone) ObjectUtil.bytesToObject(b);//反序列化
System.out.println("t1对象的name:"+t1.name);
System.out.println("t2对象的name:"+t2.name);
System.out.println("分割线-------------");
System.out.println("t1对象的hash值为:"+t1.hashCode());
System.out.println("t2对象的hash值为:"+t2.hashCode());
System.out.println("分割线-------------");
System.out.println("t1中的obj对象的hash值为:"+t1.obj.hashCode());
System.out.println("t2中的obj对象的hash值为:"+t2.obj.hashCode());
}
class Bean implements Serializable{
private static final long serialVersionUID = 1L;
}
}
结果如下`,证明对象的属性被深克隆下来了
t1对象的name:ilt
t2对象的name:ilt
分割线-------------
t1对象的hash值为:1847546936
t2对象的hash值为:812610706
分割线-------------
t1中的obj对象的hash值为:1164730192
t2中的obj对象的hash值为:1699624469