java中的拷贝
JAVA对象拷贝分为两种方式,一种是引用拷贝(浅拷贝 ),一种是对象拷贝
- 引用拷贝: 和对象拷贝的不同之处在于,引用拷贝只会生成一个新的对象引用地址,但两个地址其最终指向的还是同一个对象
- 对象拷贝:这种方式会重新生成一个新的对象,生成的新对象与原来的对象没有任何关联
- 对象浅拷贝:新对象与原来的对象没有关系,但是如果对象中又引用类型的话,那么这个对象是不会再分配地址的
- 对象深拷贝:新对象与其中的引用对象都重新分配地址
引用拷贝图片:
引用拷贝代码:
User user1 = new User();
User user2 = user1; // 进行引用拷贝
通过修改user2的值可以引起user1中的变化
对象拷贝中的浅拷贝
需要拷贝的对象实现Cloneable 接口,再调用对象的clone方法可以实现对象的浅拷贝
图片
代码
User对象:
public class User implements Cloneable{
private String name;
private int age;
private Teacher teacher;
get,set,构造函数省略
@Override
protected Object clone() throws CloneNotSupportedException {
return (User) super.clone();
}
}
Teachet对象:
public class Teacher {
private String name;
public Teacher(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试:
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher("teacher1号");
User user1 = new User("tang`", 20);
user1.setTeacher(teacher);
User clone = (User) user1.clone();
clone.getTeacher().setName("teacher2号");
System.out.println(user1.getTeacher().getName());
}
}
输出的结果为:teacher2号
结论:
- clone修改了name之后并没有影响user1的name,这说明clone和user1对象是独立的
- clone修改了teacher 对象属性之后user1的teacher对象属性也同时改变了,这说明对象的clone方法并不会把其对象中引用的其他对象进行拷贝,这也是我们俗称的浅拷贝
疑问? 为什么浅拷贝不会拷贝其引用的对象?
- 不给其他类强加意义:这个就好比,User类为了能进行浅拷贝就实现了Cloneable 接口,但是其引用对象Teacher没有实现Cloneable 也许说明他本身就不想被拷贝,如果在拷贝User的情况下,同时也把Teacher拷贝了,这不就等于干了一件没有遵循他人同意的事,干了之后人家还不知道,傻傻的以为没人可以通过clone来拷贝出另外一个Teacher
- 不破坏其原来对象的代码逻辑:如果User引用的Teacher 是个单例模式的对象,那如果在User拷贝的时候同时也拷贝出了一个Teacher 那是不是就会破坏Teacher这个单例模式对象的逻辑初衷
对象拷贝中的深拷贝
对象需要实现Serializable接口
public class User implements Serializable
public class Teacher implements Serializable
图片:
代码:
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Teacher teacher = new Teacher("teacher1号");
User user1 = new User("我是user1", 20);
user1.setTeacher(teacher);
// 序列化写入流中
ByteOutputStream byteOutputStream = new ByteOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
objectOutputStream.writeObject(user1);
// 反序列化生成user2对象
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteOutputStream.getBytes()));
User user2 = (User) objectInputStream.readObject();
user2.setName("我是user2");
user2.getTeacher().setName("teacher2号");
System.out.println("user1的teacherName: " + user1.getTeacher().getName());
System.out.println("user1的name: " + user1.getName());
}
}
输出的结果为:
user1的teacherName: teacher1号
user1的name: 我是user1
进行深拷贝后,改变User2对象中的属性不会对原来User1对象中的属性有任何影响,这说明,User1和User2 不管是属性还是其引用对象都是重新生成互不关联的两个对象
深度拷贝的工具类(适用于所有类型):
public class BeanUtil {
public static <T> T cloneTo(T src) throws RuntimeException {
ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
ObjectOutputStream out = null;
ObjectInputStream in = null;
T dist = null;
try {
out = new ObjectOutputStream(memoryBuffer);
out.writeObject(src);
out.flush();
in = new ObjectInputStream(new ByteArrayInputStream(memoryBuffer.toByteArray()));
dist = (T) in.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (out != null) {
try {
out.close();
out = null;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (in != null) {
try {
in.close();
in = null;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
return dist;
}
}