0%

浅拷贝和深拷贝

java的浅拷贝和深拷贝

clone方法

clone是定义一个Object类下基本方法之一:

1
protected native Object clone() throws CloneNotSupportedException;

使用的时候需要继承object对象,并且为了可以使其它类调用该方法,覆写克隆方法时必须将其作用域设置为public.

浅拷贝

浅拷贝就拷贝了对象本身,属性值不变,也就是说对象里面的引用还是原来对象里面的引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A implements Cloneable {
int a = 0;
int[] b = {1, 2};

@Override
protected Object clone() throws CloneNotSupportedException {
A a = null;
try {
a = (A) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return a;
}
}

测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
A a = new A();
A b = (A) a.clone();
System.out.println(b.a);
for (int i :b.b) {
System.out.print(i);
}
b.a = 1;
b.b[0] = 3;
b.b[1] = 4;
System.out.println(a.a);
for (int i :a.b) {
System.out.print(i);
}

1
2
3
测试结果是:    
0 1,2
0 3,4

因为a是基本类型所以值不变,但是b是引用类型,所以值也被改变了

深拷贝

和浅拷贝就一些细微区别,深拷贝是把对象中的属性也进行了一个拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A implements Cloneable {
int a = 0;
int[] b = {1, 2};

@Override
protected Object clone() throws CloneNotSupportedException {
A a = null;
try {
a = (A) super.clone();
// 对属性进克隆
a.b = b.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return a;
}
}
1
2
3
测试结果是:    
0 1,2
0 1,2

循环引用

如果类中的对象引用了其他的对象,那么一次次去clone显然不现实

借助java的序列化,A需要实现序列化接口,而且A中使用的所有对象都要实现序列化接口,否则会抛出NotSerializableException异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    @Override
protected Object clone() throws CloneNotSupportedException {
A a = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
a = (A) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

return a;
}