浅拷贝例子:
public class Thing implements Cloneable{
private ArrayList<String> list = new ArrayList<>();
@Override
public Thing clone(){
Thing thing = null;
try {
thing = (Thing) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
System.out.println("克隆失败");
}
return thing;
}
public void setValue(String value){
this.list.add(value);
}
public ArrayList getValue(){
return this.list;
}
public class main {
public static void main(String[] args) {
Thing thing = new Thing();
thing.setValue("张三");
Thing cloneThing= thing.clone();
cloneThing.setValue("李四");
System.out.println(thing.getValue());
}
}
运行结果:
原型模式克隆出来的对象应该是相互独立的,但是结果为什么是[张三,李四]
这是因为object类的clone方法只拷贝本对象,其对象内部的数组,引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就是浅拷贝。两个对象共用一个私有变量。这是一种非常不安全的方式。
原始类型会被拷贝(int,double,long。。。),String类型也会被拷贝
引用类型不会被拷贝
使用原型类型时,引用的成员变量必须满足两个条件才不会被拷贝
1.是类的成员变量,而不是方法内的变量
2.必须是一个可变的引用对象,而不是一个原始类型或者不可变对象
深拷贝:
public class Thing implements Cloneable{
private ArrayList<String> list = new ArrayList<>();
@Override
public Thing clone(){
Thing thing = null;
try {
thing = (Thing) super.clone();
thing.list = (ArrayList)this.list.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
System.out.println("克隆失败");
}
return thing;
}
public void setValue(String value){
this.list.add(value);
}
public ArrayList getValue(){
return this.list;
}
}
这样把引用对象也相应的拷贝一份,这样就叫做深拷贝,这样就实现了完全拷贝
注意:
1.深拷贝和浅拷贝要分开实现,不然会导致程序变得非常复杂
2.带有final类型的变量是不可以进行拷贝的,这样是无法实现深拷贝
这是因为final关键字的特性
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。