数组的复制
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) 复制指定的数组,用空值截断或填充(如有必要),以便复制具有指定的长度。 |

浙公网安备 33010602011771号