文章目录
浅拷贝与深拷贝
简单阐述
- 浅拷贝:仅仅拷贝对象本身,而不拷贝对象包含的引用指向的对象
- 深拷贝:不仅拷贝对象本身,而且拷贝对象包含的引用指向的对象
两者的区别
在需要拷贝的对象中包含引用对象时,是否将引用对象也进行拷贝(重新在堆空间中创建一个对象)
相关IO流简介
ByteArrayOutputStream
- 在创建它的实例时,可以创建字节数组输出流,同时内存会为该输出流创建一个byte型的数组缓冲区,将捕获的数据转换成字节数组放在内存缓冲区中
ByteArrayInputStream
- 可以将内存缓冲区中的字节数组转化为输入流,其中缓冲区会随着数据的不断写入而自动增长,可使用 toByteArray() 和 toString() 获取数据
PS:ByteArrayOutputStream
和 ByteArrayInputStream
不需要关闭流。即使关闭,对应的方法还是可以使用,因为它们是内存读写流,字节数组是它的成员变量,当数组不再使用时会被Java的垃圾回收机制回收。
ObjectOutputStream
- 构造方法中传递字节输出流,保存基本类型数据或对象,实现序列化(见后)
- 常搭配
.writeObject
将对象写入文件
ObjectInputStream
- 读取基本类型数据或对象,实现反序列化
- 常搭配
.readObject
将文件中数据还原成对象
序列化简要说明
简单描述
序列化是指把对象转换为字节序列的过程,而反序列化是指把字节序列恢复为对象的过程。
好处
可将任何实现了Serializable
接口的对象转化为字节数据,以实现数据的持久化(永久地保存到硬盘上),也可实现实现远程通信(即在网络上传送对象的字节序列)
注意
- 要序列化的对象不能被
static
和transient
修饰 - 要序列化的类和要引用类型属性必须实现
Serializable
和Externalizable
两个接口之一
InvalidClassException异常
-
若把一个对象序列化后又进行修改,在未序列化的情况下又将其反序列化,就会出现该异常。
-
解决方法:在创建对象时,提前给对象创建一个序列号
private static final long serialVersionUID=1L;
IO流实现深拷贝
示例
例如若要为Point
类实现深拷贝,可以这样写:
class Point implements Serializable {//设置Point类
int x, y;
void setXY(int m, int n) {
x = m;
y = n;
}
public Point myCopy() throws IOException, ClassNotFoundException {//深拷贝方法实现
// 保存对象为字节数组——序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 从字节数组中读取拷贝对象——反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Point) ois.readObject();
}
}
public class Reference {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Point p1, p2;
p1 = new Point();
p2 = new Point();
System.out.println("p1 的引用: " + p1);
System.out.println("p2 的引用: " + p2);
p1.setXY(1111, 2222);
p2.setXY(-100, -200);
Point p3 = p2.myCopy();//深拷贝方法的使用
System.out.println("p3 的引用: " + p3);//检验深拷贝结果
System.out.println("p1 的 x, y 坐标: " + p1.x + ", " + p1.y);
System.out.println("p2 的 x, y 坐标: " + p2.x + ", " + p2.y);
System.out.println("p3 的 x, y 坐标: " + p3.x + ", " + p3.y);//检验深拷贝结果
p1 = p2;//浅拷贝
p1.setXY(0, 0);
System.out.println("p1 的引用: " + p1);//浅拷贝结果
System.out.println("p2 的引用: " + p2);
System.out.println("p3 的引用: " + p3);//检验深拷贝结果
System.out.println("p1 的 x, y 坐标: " + p1.x + ", " + p1.y);//浅拷贝结果
System.out.println("p2 的 x, y 坐标: " + p2.x + ", " + p2.y);
System.out.println("p3 的 x, y 坐标: " + p3.x + ", " + p3.y);//检验深拷贝结果
}
}
本地运行结果
p1 的引用: Point@b4c966a
p2 的引用: Point@1d81eb93
p3 的引用: Point@33833882
p1 的 x, y 坐标: 1111, 2222
p2 的 x, y 坐标: -100, -200
p3 的 x, y 坐标: -100, -200
p1 的引用: Point@1d81eb93
p2 的引用: Point@1d81eb93
p3 的引用: Point@33833882
p1 的 x, y 坐标: 0, 0
p2 的 x, y 坐标: 0, 0
p3 的 x, y 坐标: -100, -200