1.什么是浅拷贝
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
- 如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
如下demo:
List<String> string = Arrays.asList("abc", "bc", "efg"); List arrList = new ArrayList(string); List<String> strings2 = arrList; System.out.println("未删除元素前的原始list大小"+arrList.size()); System.out.println("未删除元素前的模拟浅拷贝list大小"+strings2.size()); Iterator<String> it = arrList.iterator(); while (it.hasNext()){ String s = it.next(); if(s.equals("abc")){ it.remove(); } } System.out.println("删除元素后的原始list大小"+arrList.size()); System.out.println("删除元素后的模拟拷贝list大小"+strings2.size()); String a = "aaaaa"; String b = a; System.out.println("原始基本对象"+a); System.out.println("模拟拷贝对象"+b); a = "cccccc"; System.out.println("改变值之后的原始基本对象"+a); System.out.println("改变值之后的模拟拷贝基本对象"+b);
输出结果为:
未删除元素前的原始list大小3
未删除元素前的模拟浅拷贝list大小3
删除元素后的原始list大小2
删除元素后的模拟拷贝list大小2
原始基本对象aaaaa
拷贝拷贝对象aaaaa
改变值之后的原始基本对象cccccc
改变值之后的模拟拷贝基本对象aaaaa
由上面的这个例子可以指导,在将arrList赋值给strings2时,两者指向的是同一个内存地址,因此当arrList的大小改变时,strings2的大小也跟着改变。
二、什么是深拷贝
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
序列化实现深拷贝
demo:
public class DouBi implements Serializable {
private int x;
private int y;
public DouBi (int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "x=" + x + ", y=" + y;
}
}
private void test3() {
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
// 创建原始的可序列化对象
DouBi c1 = new DouBi(100, 100);
System.out.println("原始的对象 = " + c1);
DouBi c2 = null;
// 通过序列化实现深拷贝
ByteArrayOutputStream bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
// 序列化以及传递这个对象
oos.writeObject(c1);
oos.flush();
ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bin);
// 返回新的对象
c2 = (DouBi) ois.readObject();
// 校验内容是否相同
System.out.println("复制后的对象 = " + c2);
// 改变原始对象的内容
c1.setX(200);
c1.setY(200);
// 查看每一个现在的内容
System.out.println("查看原始的对象 = " + c1);
System.out.println("查看复制的对象 = " + c2);
} catch (IOException e) {
System.out.println("Exception in main = " + e);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
```
- 输出结果如下:
```
2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 原始的对象 = x=100, y=100
2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 复制后的对象 = x=100, y=100
2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 查看原始的对象 = x=200, y=200
2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 查看复制的对象 = x=100, y=100
三、如何选择拷贝方式
- 如果对象的属性全是基本类型的,那么可以使用浅拷贝。
- 如果对象有引用属性,那就要基于具体的需求来选择浅拷贝还是深拷贝。
- 意思是如果对象引用任何时候都不会被改变,那么没必要使用深拷贝,只需要使用浅拷贝就行了。如果对象引用经常改变,那么就要使用深拷贝。没有一成不变的规则,一切都取决于具体需求。