clone()方法(浅复制、深复制)

1. 对象和引用的区别

java在处理基本数据类型(如int、char、double等)时,都是采用按值传递(传递的是输入参数的复制),除此之外其他类型都是按引用传递(传递的是对象的一个引用)。

对象除了在函数调用时是引用传递,在使用“=”赋值时呀采用引用传递,示例代码如下:

class Obj {
    private int aInt = 0; 

    public int getAInt() { return aInt; }
    public void setAInt(int a) { aInt = a; }
    public void changeAInt() { this.aInt = 1; }
}

public class TestRef {
    public static void main(String[] args) {
        Obj a = new Obj();
        Obj b = a; // clone()函数返回的是一个新的对象而不是一个引用
        b.changeAInt();
        System.out.println("a = " + a.getAInt());
        System.out.println("b = " + b.getAInt());
    }
}/* Output:
a = 1
b = 1
*///~

在实际编程中,经常会遇到从某个已有对象A创建出另外一个与A具有相同状态的对象B,并且对B的修改不会影响到A的状态,例如,Prototype(原型)模式中,就需要clone一个对象实例。在java中,仅仅通过简单的复制操作显然无法打到这个目的,而java提供了一个简单有效的clone()方法来满足这个需求。

2. clone()方法

java中所有的类默认都是继承自 Object 类,而 Object 类中提供了一个 clone() 方法。这个方法的作用是返回一个 Object 对象的复制。这个复制函数返回的是一个新的对象而不是一个引用。
以下是使用 clone() 方法的步骤:

  1. 实现clone的类首先需要实现 Cloneable 接口。Cloneable 接口实际上是一个标识接口,没有任何接口方法。
  2. 在类中重写 Object 类中的 clone() 方法。
  3. 在 clone() 方法中调用 super.clone()。无论 clone 类的继承接口是什么,super.clone() 都会直接或间接调用 java.lang.Object 类的 clone() 方法。
  4. 把浅复制的引用指向原型对象新的克隆体。
 class Obj implements Cloneable {
    private int aInt = 0; // 基本数据类型

    public int getAInt() { return aInt; }
    public void setAInt(int a) { aInt = a; }
    public void changeAInt() { this.aInt = 1; }

    public Object clone() {
        Obj o = null;
        try {
            o = (Obj)super.clone();
        } catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return o;
    }
}

public class TestClone {
    public static void main(String[] args) {
        Obj a = new Obj();
        Obj b = (Obj)a.clone(); // clone()函数返回的是一个新的对象而不是一个引用
        b.changeAInt();
        System.out.println("a = " + a.getAInt());
        System.out.println("b = " + b.getAInt());
    }
}/* Output:
a = 0
b = 1
*///~

当类中只有一些基本数据类型时,采用上述方法就可以了。但是当类中包含了一些对象时,就需要用到深复制了
深复制的实现方法是在对象调用 clone() 方法完成复制后,接着对对象中的非基本类型的属性也调用 clone() 方法完成深复制。示例如下:

 import java.util.*;
 class Obj implements Cloneable {
    private Date birth = new Date(); // 非基本数据类型

    public Date getBirth() { return birth; }
    public void setBirth(Date birth) { this.birth = birth; }
    @SuppressWarnings("deprecation")
    public void changeDate() { this.birth.setMonth(8); }

    public Object clone() {
        Obj o = null;
        try {
            o = (Obj)super.clone();
        } catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        // 实现深复制,对对象中的非基本类型(birth)进行复制。
        o.birth = (Date)this.getBirth().clone(); // 这句是针对非基本数据类型的
        return o;
    }
}

public class TestClone {
    public static void main(String[] args) {
        Obj a = new Obj();
        //Obj b = a; // 传递的是引用
        Obj b = (Obj)a.clone(); // clone()函数返回的是一个新的对象而不是一个引用
        b.changeDate();
        System.out.println("a.birth = " + a.getBirth());
        System.out.println("b.birth = " + b.getBirth());
    }
}/* Output:
a.birth = Wed Mar 22 18:34:24 CST 2017
b.birth = Fri Sep 22 18:34:24 CST 2017
*///~

3. 深复制与浅复制

在编程时,如何选择使用哪种复制方式呢?

首先,检查类有无非基本类型(即对象)的数据成员。若没有,则返回 super.clone()即可;若有,确保类中包含的所有非基本类型的成员变量都实现了深复制。

 Object o = super.clone(); //先执行浅复制
 对每一个对象 attr 执行以下语句:
 o.attr = this.getAttr().clone();
 最后返回o.

需要注意的是,clone() 方法的保护机制在 Object 中 clone() 是被生命为 protrcted 的。

浅复制和深复制有什么区别?

浅复制(Shallow Clone):被复制对象的所有变量都含有与原来对象相同的值,而所有对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它的引用对象。

深复制(Deep Clone):被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制的新对象。换言之,深复制把复制的对象所引用的对象都复制了一遍。

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值