java原型模型以及浅拷贝深拷贝问题

原型模式的定义与特点
原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。
原型模式的结构与实现
由于 Java 提供了对象的 clone() 方法,所以用 Java 实现原型模式很简单。这里要重点解释的是原型模式的浅拷贝深拷贝的问题。
看了很多博客都没有说清这个问题。
我们先看看引用复制是啥样的。

public class Student implements Cloneable{
    private int StuId;
    private String StuName;
    private int StuAge;
    public Student(int stuId, String stuName, int stuAge) {
        super();
        StuId = stuId;
        StuName = stuName;
        StuAge = stuAge;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }//深拷贝的重新代码省去,很简单!这里的super.clone调用的是Object的方法,他默认只拷贝基本类型数据。要用深拷贝,再拷贝一份引用类型就OK,如果引用类型过多,建议用序列化的形式实现!
}
public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student stu1 = new Student(0,"zhangsan",20);        
        Student stu2 = stu1;
        System.out.println("stu1 = " + stu1);
        System.out.println("stu2 = " + stu2);
    }
}
运行结果:
stu1 = Student@3c635421
stu2 = Student@3c635421

上图中,stu1和stu2都是指向同一个类!!他们的地址相同。
问题来了,浅拷贝出来的地址相同嘛?

public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student stu3 = new Student(1,"lisi",20);
        Student stu4 = (Student) stu3.clone();
        System.out.println("stu3 = " + stu3);
        System.out.println("stu4 = " + stu4);
        System.out.println(stu3.StuName==stu4.StuName);
    }
}
运行结果:
stu3 = Student@7bc2f501
stu4 = Student@3c635421
true

可以看到,结果不同!这里可以看到Student类中第二个为String引用类型的,复制出的stu3和stu4的String类型的地址相同!
浅拷贝:java有两种数据类型,一种是8种数据基本类型(int ,char等),一种是引用类型(类等)。浅拷贝就是单纯的拷贝了基本的8种类型,而对于引用类型,并没有拷贝出单独的一份,仍然用的是原来引用的地址。

OK,以上解释了深拷贝和引用复制的区别!区别只有一点,引用复制的两个类地址都一样,住一间房子!浅拷贝的住两个房子,但是引用类型的地址都是一样的。来个图:

在这里插入图片描述
如果是引用复制,那么栈内存中左边都是在一个房子住!

深拷贝:深拷贝就是在堆内存中,将引用对象复制一份,所以引用类型深拷贝的地址是不相等的,深拷贝就是深度的拷贝,他不止拷贝基本类型,也拷贝引用类型。
在这里插入图片描述
要注意的是String!!!
我们再次重复刚刚的代码(要用序列化或者重写clone才能达到深拷贝的效果)这里默认已经重写了clone方法!

String毫无疑问它是引用类型。
public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student stu3 = new Student(1,"lisi",20,new Address("安徽","合肥"));//我们这里加上一个Address
        Student stu4 = (Student) stu3.clone();
        System.out.println("stu3 = " + stu3);
        System.out.println("stu4 = " + stu4);
        System.out.println(stu3.StuName==stu4.StuName);
        System.out.println(stu3.getAddress()==stu4.getAddress());
    }
}
运行结果:
stu3 = Student@7bc2f501
stu4 = Student@3c635421
true//这里的结果竟然还是!!!true
false//哦豁,这里的结果错了??为什么叻

答案是String并不是简单的引用类型,它是一个final修饰的引用类型!不可更改,所以还是true!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值