第11条:谨慎地使用clone

  • Object clone方法受保护protected,需要覆写public Xxx clone() {return super.clone();并修正任何需要修正的域:可变引用对象}
  • clone方法约定:x.clone() != x; x.clone().equals(x); x.clone().getClass() == x.getClass()
  • 克隆复杂对象:或者直接操作对象及其克隆对象的内部状态的clone方法,要么调用super.clone()返回后将所有域置空白状态virgin state然后重新产生对象的状态。
  • 另一个实现对象拷贝的方法是提供一个copy constructor 或者 copy factory,带一个参数,参数类型是通过该类实现的接口(所有集合提供了一个copy constructor参数类型是Collection或者Map,HashSet s: new TreeSet(s))。
  • 除非拷贝数组,否则不用clone方法。

以下是转转载,转载自一个转载,比较简单清晰
https://blog.csdn.net/AlbenXie/article/details/89739773

java数组拷贝主要有四种方法,分别是循环赋值,System.arraycopy(),Arrays.copyOf()(或者Arrays.copyOfRange)和clone()方法。下面分别介绍一下这几种拷贝。

1、循环拷贝(速度相对比较慢)

循环拷贝其实没什么好说的啦,就是用一个for循环进行元素的逐个拷贝,进行深拷贝或者浅复制这个大家可以自己把握。

2、System.arraycopy(浅拷贝)

这个是系统提供的拷贝方式,也是我们推荐使用的拷贝方式,它是浅拷贝,也就是说对于非基本类型而言,它拷贝的是对象的引用,而不是去新建一个新的对象。通过它的代码我们可以看到,这个方法不是用java语言写的,而是底层用c或者c++实现的,因而速度会比较快。

``` public static native void arraycopy (Object src, int srcPos,Object dest, int destPos,int length); ```

通过源代码我们可以看到,关键字native说明它不是用java语言写的,而是调用其他语言的代码。

3、Arrays.copyOf(浅拷贝)

这个方法也是浅拷贝,为什么呢?我们看一下它的源代码就知道了。

public static byte[] copyOfRange(byte[] original, int from, int to) {
    int newLength = to - from;
    if (newLength < 0)
        throw new IllegalArgumentException(from + " > " + to);
    byte[] copy = new byte[newLength];
    System.arraycopy(original, from, copy, 0,Math.min(original.length - from, newLength));
    return copy;
}

实际上它调用的就是System.arraycopy,所以肯定也是浅拷贝。

4、对象拷贝(Object.clone)

clone()比较特殊,对于对象而言,它是深拷贝(我觉得这句话是说对于对象本身而言,内部各域仍然是浅copy的吧),但是对于数组而言,它是浅拷贝。

首先讲一下对象的拷贝,它是深拷贝,大家可以用对象去测试一下。下面我们看一下它的源代码:

protected native Object clone() throws CloneNotSupportedException;

这里也有native关键字,所以也是底层的c语言实现的。 
还要注意的是,这里修饰符是protected,也就是说,我们创建了一个Object类以后,是不能直接调用这个clone()方法的,因为protected关键字只允许同一个包内的类和它的子类调用,所以我们声明一个object类时,肯定不是同一个包内,所以就不能去调用它。

要调用这个方法,就需要我们写一个类,然后声明实现cloneable接口就好了,不需要去显式地声明继承于object,因为java中的类如果不显示说明父类的话,默认父类就是object。然后我们继承这个方法:

@Override
public Object clone() throws CloneNotSupportedException {
    // TODO Auto-generated method stub
    return super.clone();
}

这里需要是,为了能够在不同包内去调用这个方法,我们需要把这个权限升级为public。现在我们就可以调用这个类的clone()方法去拷贝我们的类了。

5、数组拷贝

对于数组而言,它不是简单的将引用赋值为另外一个数组引用,而是创建一个新的数组。但是我们知道,对于数组本身而言,它它的元素是对象的时候,本来数组每个元素中保存的就是对象的引用,所以,拷贝过来的数组自然而言也是对象的引用,所以对于数组对象元素而言,它又是浅拷贝。我们用以下代码验证一下:

class Aby implements Cloneable{
    public int i;
    public Aby(int i) {
        this.i = i;
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        return super.clone();
    }
}
 
public class Solution {
 
    public static void main(String[] args) throws CloneNotSupportedException {
        Aby aby1 = new Aby(1);
        Aby aby2 = (Aby) aby1.clone();
        aby1.i = 2;
        System.out.println(aby1.i); //2
        System.out.println(aby2.i); //1
 
        Aby[] arr = {aby1,aby2};
 
        Aby[] arr2 = arr.clone();
        arr2[0].i = 3;
        System.out.println(arr[0].i);   //3
        System.out.println(arr2[0].i);  //3
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值