数组的复制

clone()

1. cloneable

clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。

public class CloneExample {
    private int a;
    private int b;
}
CloneExample e1 = new CloneExample();
// CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'

重写 clone() 得到以下实现:

public class CloneExample {
    private int a;
    private int b;

    @Override
    public CloneExample clone() throws CloneNotSupportedException {
        return (CloneExample)super.clone();
    }
}
CloneExample e1 = new CloneExample();
try {
    CloneExample e2 = e1.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}
java.lang.CloneNotSupportedException: CloneExample

以上抛出了 CloneNotSupportedException,这是因为 CloneExample 没有实现 Cloneable 接口。

应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。

public class CloneExample implements Cloneable {
    private int a;
    private int b;

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

2. 浅拷贝

拷贝对象和原始对象的引用类型引用同一个对象。

public class ShallowCloneExample implements Cloneable {

    private int[] arr;

    public ShallowCloneExample() {
        arr = new int[10];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }
    }

    public void set(int index, int value) {
        arr[index] = value;
    }

    public int get(int index) {
        return arr[index];
    }

    @Override
    protected ShallowCloneExample clone() throws CloneNotSupportedException {
        return (ShallowCloneExample) super.clone();
    }
}
ShallowCloneExample e1 = new ShallowCloneExample();
ShallowCloneExample e2 = null;
try {
    e2 = e1.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}
e1.set(2, 222);
System.out.println(e2.get(2)); // 222

3. 深拷贝

拷贝对象和原始对象的引用类型引用不同对象。

public class DeepCloneExample implements Cloneable {

    private int[] arr;

    public DeepCloneExample() {
        arr = new int[10];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }
    }

    public void set(int index, int value) {
        arr[index] = value;
    }

    public int get(int index) {
        return arr[index];
    }

    @Override
    protected DeepCloneExample clone() throws CloneNotSupportedException {
        DeepCloneExample result = (DeepCloneExample) super.clone();
        result.arr = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            result.arr[i] = arr[i];
        }
        return result;
    }
}
DeepCloneExample e1 = new DeepCloneExample();
DeepCloneExample e2 = null;
try {
    e2 = e1.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}
e1.set(2, 222);
System.out.println(e2.get(2)); // 2

4. clone() 的替代方案

使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。

public class CloneConstructorExample {

    private int[] arr;

    public CloneConstructorExample() {
        arr = new int[10];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }
    }

    public CloneConstructorExample(CloneConstructorExample original) {
        arr = new int[original.arr.length];
        for (int i = 0; i < original.arr.length; i++) {
            arr[i] = original.arr[i];
        }
    }

    public void set(int index, int value) {
        arr[index] = value;
    }

    public int get(int index) {
        return arr[index];
    }
}
CloneConstructorExample e1 = new CloneConstructorExample();
CloneConstructorExample e2 = new CloneConstructorExample(e1);
e1.set(2, 222);
System.out.println(e2.get(2)); // 2

Java中四种复制数组的方法

JAVA语言的下面几种数组复制方法中,哪个效率最高?

B.效率:System.arraycopy > clone > Arrays.copyOf > for循环

1、System.arraycopy的用法:

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

参数:src - 源数组。srcPos - 源数组中的起始位置。dest - 目标数组。destPos - 目标数据中的起始位置。 length - 要复制的数组元素的数量

应用实例:

public class Main{
	public static void main(String[] args) {
		int[] a1={1, 2, 3, 4, 5, 6};
        int[] a2={7, 8, 9, 10, 11, 12, 13};

        System.arraycopy(a1, 1, a2, 2, 3);
        System.out.print("copy后结果:");
        for(int i=0;i<a2.length;i++){
            System.out.print(a2[i]+" ");
        }
	}
}

运行结果:

copy后结果:7 8 2 3 4 12 13 

2、clone 的用法:

java.lang.Object类的clone()方法为protected类型,不可直接调用,需要先对要克隆的类进行下列操作:

首先被克隆的类实现Cloneable接口;然后在该类中覆盖clone()方法,并且在该clone()方法中调用super.clone();这样,super.clone()便可以调用java.lang.Object类的clone()方法。

应用实例:

//被克隆的类要实现Cloneable接口
class Cat implements Cloneable 
{
	private String name;
	private int age;
	public Cat(String name,int age)
	{
		this.name=name;
		this.age=age;
	}
	//重写clone()方法
	protected Object clone()throws CloneNotSupportedException{  
        return super.clone() ;  
    }
}
public class Clone {
	public static void main(String[] args) throws CloneNotSupportedException {
 
		Cat cat1=new Cat("xiaohua",3);
		System.out.println(cat1);
		//调用clone方法
		Cat cat2=(Cat)cat1.clone();
		System.out.println(cat2);
	}
}

3、复制引用和复制对象的区别

复制引用:是指将某个对象的地址复制,所以复制后的对象副本的地址和源对象相同,这样,当改变副本的某个值后,源对象值也被改变;

复制对象:是将源对象整个复制,对象副本和源对象的地址并不相同,当改变副本的某个值后,源对象值不会改变;

Cat cat1=new Cat("xiaohua",3);//源对象
System.out.println("源对象地址"+cat1);
//调用clone方法,复制对象
Cat cat2=(Cat)cat1.clone();
Cat cat3=(Cat)cat1;//复制引用
System.out.println("复制对象地址:"+cat2);
System.out.println("复制引用地址:"+cat3);

输出结果:

可以看出,复制引用的对象和源对象地址相同,复制对象和源对象地址不同

4、Arrays.copyOf 的用法:

Arrays.copyOf有十种重载方法,复制指定的数组,返回原数组的副本。

Modifier and Type Method and Description
static boolean[] copyOf(boolean[] original, int newLength) 使用 false (如有必要)复制指定的数组,截断或填充,以使副本具有指定的长度。
static byte[] copyOf(byte[] original, int newLength) 复制指定的数组,用零截取或填充(如有必要),以便复制具有指定的长度。
static char[] copyOf(char[] original, int newLength) 复制指定的数组,截断或填充空字符(如有必要),以便复制具有指定的长度。
static double[] copyOf(double[] original, int newLength) 复制指定的数组,用零截取或填充(如有必要),以便复制具有指定的长度。
static float[] copyOf(float[] original, int newLength) 复制指定的数组,用零截取或填充(如有必要),以便复制具有指定的长度。
static int[] copyOf(int[] original, int newLength) 复制指定的数组,用零截取或填充(如有必要),以便复制具有指定的长度。
static long[] copyOf(long[] original, int newLength) 复制指定的数组,用零截取或填充(如有必要),以便复制具有指定的长度。
static short[] copyOf(short[] original, int newLength) 复制指定的数组,用零截取或填充(如有必要),以便复制具有指定的长度。
static <T> T[] copyOf(T[] original, int newLength) 复制指定的数组,用空值截断或填充(如有必要),以便复制具有指定的长度。
static <T,U> T[] copyOf(U[] original, int newLength, 类<? extends T[]> newType) 复制指定的数组,用空值截断或填充(如有必要),以便复制具有指定的长度。

参考:CS-Notes
Kunrong

posted @ 2020-06-01 14:55  g_curry  阅读(147)  评论(0)    收藏  举报