Java 浅复制和深复制

Java 浅复制和深复制

目录

Java 浅复制和深复制

java创建对象的方式:

浅复制和深复制

浅复制:复制引用

深复制:复制对象

Shape:代码

总结:


 

在学习原型模式中,里面有知识点浅复制和深复制,进行深入一点的学习:

 

java创建对象的方式:

1,使用new创建对象

   new操作符是分配内存。程序执行到new操作符时,进行对象的初始化,先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。

 

2,使用clone方法来复制对象

   clone在第一步也是分配内存,调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。

 

浅复制和深复制

浅复制:复制引用

要想获取对象的内存地址应使用System.identityHashCode()方法

 

代码:

public static void main(String[] args){
    testShallowObject();
}



public static void testShallowObject(){

    System.out.println("====== Object =======");

    Shape shape1 = new Shape("pink","circle");

    Shape shape2 = shape1;

    System.out.println("init: shape1: "+ shape1.toString());

    System.out.println("init: shape2: "+ shape2.toString());

    shape2.setColor("green");

    shape2.setType("rectangle");

    System.out.println("change: shape1: "+ shape1.toString());

    System.out.println("change: shape2: "+ shape2.toString());

    System.out.println("内存地址: shape1: "+ System.identityHashCode(shape1));

    System.out.println("内存地址: shape2: "+ System.identityHashCode(shape2));

}

 

结果:

====== Object =======
init: shape1: Shape{color='pink', type='circle'}
init: shape2: Shape{color='pink', type='circle'}
change: shape1: Shape{color='green', type='rectangle'}
change: shape2: Shape{color='green', type='rectangle'}

给shape2设置属性的时候,把shape1的内容也改变了。这个是复制引用。

new Shape()是创建了一个真正的对象, shape1和shape2只是两个对象的引用。代码中打印地址可以发现地址值是相同的,既然地址都是相同的,那么肯定是同一个对象。shape1和shape2只是指向了一个相同的对象的两个不同的引用而已。可以把这种现象叫做引用的复制。内存中的地址情景如图:

 

 

深复制:复制对象

  使用clone()方法进行复制

代码:

public static void main(String[] args){ 
    testDeepObject();
}



public static void testDeepObject(){

    System.out.println("====== Object =======");

    Shape shape1 = new Shape("pink","circle");

    System.out.println("========= clone =========");

    Shape shape3 = (Shape) shape1.clone();

    System.out.println("init: shape1: "+ shape1.toString());

    System.out.println("init: shape3: "+ shape3.toString());

    shape3.setColor("blue");

    shape3.setType("triangle");

    System.out.println("change: shape1: "+ shape1.toString());

    System.out.println("change: shape3: "+ shape3.toString());

    System.out.println("内存地址: shape1: "+ System.identityHashCode(shape1));

    System.out.println("内存地址: shape3: "+ System.identityHashCode(shape3));

}

 

结果:

 

====== Object =======
========= clone =========
init: shape1: Shape{color='pink', type='circle'}
init: shape3: Shape{color='pink', type='circle'}
change: shape1: Shape{color='pink', type='circle'}
change: shape3: Shape{color='blue', type='triangle'}
内存地址: shape1: 258952499
内存地址: shape3: 603742814

  给shape3设置属性的时候,把shape1的内容没有变化。这个是复制对象。

new Shape()是创建了一个真正的对象, 而(Shape) shape1.clone()复制了对象。shape1和shape3是两个不同的对象。代码中打印地址可以发现地址值是不同的。shape1和shape3分别指向了不同的两个对象,可以把这种现象叫做对象的复制。内存中的地址情景如图:

 

Shape:代码

public class Shape implements Cloneable {

    private String color;

    private String type;

    public Shape(String color, String type) {

        this.color = color;

        this.type = type;

    }

    public String getColor() {

        return color;

    }

    public void setColor(String color) {

        this.color = color;

    }

    public String getType() {

        return type;

    }

    public void setType(String type) {

        this.type = type;

    }

    @Override

    public Object clone() {

        Object clone = null;

        try {

            clone = super.clone();

        } catch (CloneNotSupportedException e) {

            e.printStackTrace();

        }

        return clone;

    }

    @Override

    public String toString() {

        return "Shape{" +

                "color='" + color + '\'' +

                ", type='" + type + '\'' +

                '}';

    }

}

 

Clone的用法和说明

(1)clone方法将对象复制了一份并返回给调用者。

一般而言,clone()方法满足:

    1,对任何的对象x,都有x.clone() !=x 克隆对象与原对象不是同一个对象

    2,对任何的对象x,都有x.clone().getClass()= =x.getClass()克隆对象与原对象的类型一样。

   3,如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

(2)为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。

   在派生类中覆盖基类的clone()方法,并声明为public。 在派生类的clone()方法中,调用super.clone()。 在派生类中实现Cloneable接口。

 

说明:

(1)为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。

(2)那么clone类为什么还要实现Cloneable接口呢?点击Cloneable接口会发现,

public interface Cloneable {

}

Cloneable接口是不包含任何方法的!

其实这个接口仅仅是一个标志,而且这个标志也仅仅是针对Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的clone()方法(也就是调用了super.Clone()方法),那么Object的clone()方法就会抛出java.lang.CloneNotSupportedException异常。

 

总结:

  了解了什么是浅复制和深复制,在使用对象类型,进行复制的时候,就更容易清楚要注意什么。

   对象类型的深复制具体处理看 java 深复制处理

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天狼1222

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值