java中clone的学习

今天看了下effective java 中的clone的使用,对其有了一点了解,下面就把自己理解的写下来,以便以后运用~~~~
java中要实现对象的拷贝,就可以用Object的clone()方法,对于自己的写的类要实现cloneable接口,并且覆盖父类的clone()方法。
传统的对象赋值如:

public class Test{
private String str;
public Test(String str){
this.str = str;
}
public void setStr(String str){
this.str = str;
}
public String getStr(){
return this.str;
}
public static void main(String args[]){
Test t1 = new Test("www");
Test t2 = t1;
t2.setStr("ddd");
System.out.println(t1.getStr());//输出ddd
System.out.println(t2.getStr());//输出ddd
}
}

上面 t2 = t1只是把让t1和t2同时指向了同一块内存,对于t2的改变也会影响到t1,那如果我想要t2的改变不影响t1应该怎么办呢?
其实很简单,这就可以用到Object类的clone()方法,同时实现Cloneable接口改进后的代码,如下:

public class Test implements Cloneable{
private String str;
public Test(String str){
this.str = str;
}
public void setStr(String str){
this.str = str;
}
public String getStr(){
return this.str;
}
public static void main(String args[]) throws CloneNotSupportedException{
Test t1 = new Test("www");
Test t2 = (Test) t1.clone();
t2.setStr("ddd");
System.out.println(t1.getStr());//输出www
System.out.println(t2.getStr());//输出ddd
}
}

这样t2是一个新的对象引用,就类似于Test t2 = new Test("www"),t1和t2 指向不同的内存空间,对t2设置 值不会影响到t1。
但是这样做又会产生另一个问题,看下面的代码:

public class Test implements Cloneable{
private String str;
private HashMap<Integer, String> map = new HashMap<Integer, String>();
public Test(String str){
this.str = str;
map.put(1, "1111");
map.put(2, "2222");
map.put(3, "3333");
}
public void setStr(String str){
this.str = str;
}
public String getStr(){
return this.str;
}
public HashMap<Integer, String> getMap(){
return this.map;
}
public static void main(String args[]) throws CloneNotSupportedException{
Test t1 = new Test("www");
Test t2 = (Test) t1.clone();
t2.setStr("ddd");
System.out.println(t1.getStr());//输出www
System.out.println(t2.getStr());//输出ddd

t2.getMap().put(4, "4444");
System.out.println(t1.getMap().get(4));//输出4444(我们设想的值应该是null)
System.out.println(t2.getMap().get(4));//输出4444
}
}

可以看到上面的t1中的输出并不是null,而是4444,这是为什么呢???
其实Object类中的clone()方法,可以简单的理解为复制一个内部元素值相同的对象出来,如上面的程序,t1和t2中的map成员变量所指向的内存地址是一样的,所以你可以任意其中一个改变map的值,这样他们就不指向同一内存空间,但是你如果去修改map中的键值的话,他们两个是同时指向同一个空间的,一个改变,另一个也会改变。
解决方法如下:

public class Test implements Cloneable{
private String str;
private HashMap<Integer, String> map = new HashMap<Integer, String>();
public Test(String str){
this.str = str;
map.put(1, "1111");
map.put(2, "2222");
map.put(3, "3333");
}
public void setStr(String str){
this.str = str;
}
public String getStr(){
return this.str;
}
public HashMap<Integer, String> getMap(){
return this.map;
}

public static void main(String args[]) throws CloneNotSupportedException{
Test t1 = new Test("www");
Test t2 = (Test) t1.clone();
t2.setStr("ddd");

System.out.println(t1.getStr());//输出www
System.out.println(t2.getStr());//输出ddd

t2.getMap().put(4, "4444");
System.out.println(t1.getMap().get(4));//输出null
System.out.println(t2.getMap().get(4));//输出4444
}

@Override public Test clone(){
Test obj = null;
try {
obj = (Test) super.clone();
obj.map = (HashMap<Integer, String>) obj.map.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
}

重写clone()方法并且把成员变量也clone()一份,这样就可以解决上面的问题,对象数组也是这样处理的,事实上只要你用的对象的clone()方法,最好都重写clone()方法

@Override public Test clone(){
Test obj = null;
try {
obj = (Test) super.clone();
//clone其他类成员对象
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}

哎,总算写完了,JDK中的clone这个方法有很多问题的,所以很多大牛们都是不推荐用的,基本的问题留给以后慢慢发掘了~~~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值