一、定义
通过原型实例指定创建对象的种类,并通过拷贝这些原型实例构建新的对象。(我觉简单的说,就是一种更快更省资源的创建新的
对象的方法)
二、实例
定义什么的总是难懂,还是上实例吧!
定义一个Ball类型,实现Cloneable接口,使得这个类的对象能够被克隆。
public class Ball implements Cloneable{
public int id = -1;
public String teststring ;
public int[] num ;
public ArrayList<String> list = new ArrayList<String>();
public T t ;
@Override
protected Object clone() throws CloneNotSupportedException {
Ball ball = null ;
try {
ball = (Ball) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return ball ;
}
}
//T类型
class T{
public int t = 0;
}
测试代码如下:
Ball ball = new Ball();
ball.setId(0);
for(int i=1;i<100;i++){
try {
Ball cloneball = (Ball)ball.clone();
System.out.println(cloneball.id);
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
运行结果为:0
三、理论知识
3.1使用场景
原型模式很简单,基本上就是实现以下clone方法就好了,而且代码基本都是一样的。
3.2和new的区别
clone出来的对象是不经过构造函数构造的。也就是说Ball cloneball = (Ball)ball.clone()这句话没有用到构造函数就直接 定义了一个新的对象出来。
3.3clone出的对象的来源
clone方法是从内存中直接拷贝一个对象的数据到新开辟的内存空间中。
四、两种拷贝方式浅拷贝和深拷贝
4.1 区别
浅拷贝:在执行clone来创建对象的时候,新出来的对象其实是和原对象共享数组和引用的(除了基本数据类型)。
深拷贝:用clone生成对象后,这个对象是完全独立的,它的变量不会被其他clone出来的或者原型对象修改。
4.2实例
4.2.1浅拷贝:看下面的测试函数:
System.out.println("ball信息:");
System.out.println("id:"+ball.id+" num:"+ball.num[0]+" "+ball.num[1]+" T:"+ball.t.t+" list[0]:"+ball.list.get(0)+" string:"+ball.teststring);
System.out.println("cloneball信息:");
System.out.println("id:"+cloneball.id+" num:"+cloneball.num[0]+" "+cloneball.num[1]+" T:"+cloneball.t.t+" list[0]:"+
cloneball.list.get(0)+" string:"+cloneball.teststring);
System.out.println("两者的teststring地址是否相同:"+(ball.teststring == cloneball.teststring));
System.out.println("修改ball信息:");
ball.id = 2;
ball.num[0] = 2;
ball.num[1] = 3;
ball.t.t = 2;
ball.list.remove(0);
ball.teststring = "i am ball after change!" ;
ball.list.add("i am the first string ball.list after change !");
System.out.println("id:"+ball.id+" num:"+ball.num[0]+" "+ball.num[1]+" T:"+ball.t.t+" list[0]:"+ball.list.get(0)+" string:"+ball.teststring);
System.out.println("此时cloneball的信息变化为:");
System.out.println("id:"+cloneball.id+" num:"+cloneball.num[0]+" "+cloneball.num[1]+" T:"+cloneball.t.t+" list[0]:"+
cloneball.list.get(0)+" string:"+cloneball.teststring);
它的运行结果如下:
ball信息:
id:1 num:1 2 T:1 list[0]:i am the first string ball.list string:i am ball!
cloneball信息:
id:1 num:1 2 T:1 list[0]:i am the first string ball.list string:i am ball!
两者的teststring地址是否相同:true
修改ball信息:
id:2 num:2 3 T:2 list[0]:i am the first string ball.list after change ! string:i am ball after change!
此时cloneball的信息变化为:
id:1 num:2 3 T:2 list[0]:i am the first string ball.list after change ! string:i am ball!
仔细对比一下可以发现,修改ball中的基本数据类型变量id(int型)、teststring(string),不会导致cloneball中的
相应的变量改变,但是修改list(ArrayList)和num(int[])时就会导致cloneball中变量也改变。这就是浅拷贝。
(注意string类型的变量,在cloneball刚生成的时候里面的teststring和ball中的teststring是同一个东西,他们的地址是一样的,
但是一方的改变对另一方无影响,所以在这里把string也当做普通的数据类型处理)。
我觉得在堆里面的变量在克隆的时候都是共享的,而栈里面的东西都是会重新建立一个。
4.2.1 深拷贝
就是在拷贝对象的时候将原型类中所有的引用对象再拷贝一遍。clone方法改成:
protected Object clone() throws CloneNotSupportedException {
Ball ball = null ;
try {
ball = (Ball) super.clone();
ball.list = (ArrayList<String>) this.list.clone();
ball.t = new T();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return ball ;
}
来源:CSDN
作者:yuanGrowing
链接:https://blog.csdn.net/u011453689/article/details/50151505