Java对象复制(直接赋值,浅拷贝,深拷贝)
目录
Java对象复制
将一个对象的引用复制给另一个对象,一共有三种方式。第一种是直接赋值,第二种方式是浅拷贝,第三种是深拷贝,这三种方式实际上都是为了拷贝对象。
1,直接赋值
为了测试方便,新建两个类,没有实际的业务功能,只是为了测试。
//用了lombok插件,生成get,set方法,有参构造与无参构造@Data@AllArgsConstructor@NoArgsConstructorpublic class User { private Integer id; private String name; private Integer age; private Student student;}
@Data@NoArgsConstructor@AllArgsConstructorpublic class Student { private Integer id; private Integer score;}
public class CopyTest { public static void main(String[] args) { Student student = new Student(1, 80); User user = new User(1, "zhangSan", 25, student); User newUser=user; System.out.println(newUser.toString()); user.setAge(26); newUser.setName("zhangSan1"); System.out.println(newUser.toString()); }}
输出:
User(id=1, name=zhangSan, age=25, student=Student(id=1, score=80))User(id=1, name=zhangSan1, age=26, student=Student(id=1, score=80))
直接赋值相当于是指针赋值,newUser和user这两个对象都是指向同一个地址,只要其中任何一个改变相应的值,两个都会一起变化。
2,浅拷贝
创建一个新对象,然后将当前对象的非静态字段复制到该对象,如果字段是值类型,那么对该字段进行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。 因此,原始对象及其副本引用同一个对象。
浅拷贝需要继承Cloneable接口,重写clone()方法。
@Data@AllArgsConstructor@NoArgsConstructorpublic class User implements Cloneable { private Integer id; private String name; private Integer age; private Student student; @Override public Object clone(){ try{ return (User) super.clone(); }catch (Exception e){ e.printStackTrace(); return null; } }}
public class CopyTest { public static void main(String[] args) { Student student = new Student(1, 80); User user = new User(1, "zhangSan", 25, student); User newUser = (User) user.clone();//浅拷贝 System.out.println(newUser.toString()); //使用这种方式修改student引用,newUser是不会跟着变得,因为创建了一个新的Student类对象,而不是改变原对象的实例值 //user.setStudent(new Student(2, 90)); student.setScore(90); System.out.println(newUser.toString()); }}
输出:
User(id=1, name=zhangSan, age=25, student=Student(id=1, score=80))User(id=1, name=zhangSan, age=25, student=Student(id=1, score=90))
可以发现原对象user中的Student实例值改变后,拷贝对象newUser中的student实例值也跟着变了,说明是同一个引用。
3,深拷贝
深拷贝不仅复制对象本身,而且复制对象包含的引用指向的所有对象。
@Data@NoArgsConstructor@AllArgsConstructorpublic class Student implements Cloneable { private Integer id; private Integer score; @Override public Object clone(){ try{ return (Student) super.clone(); }catch (Exception e){ e.printStackTrace(); return null; } }}
@Data@AllArgsConstructor@NoArgsConstructorpublic class User implements Cloneable { private Integer id; private String name; private Integer age; private Student student; @Override public Object clone() { User user = null; try { user = (User) super.clone(); } catch (Exception e) { e.printStackTrace(); } user.student = (Student) student.clone();//调用student的clone方法 return user; }}
public class CopyTest { public static void main(String[] args) { Student student = new Student(1, 80); User user = new User(1, "zhangSan", 25, student); User newUser = (User) user.clone();//浅拷贝 System.out.println(newUser.toString()); //user.setStudent(new Student(2, 90));//使用这种方式修改student引用,newUser是不会跟着变得,因为创建了一个新的Student类对象,而不是改变原对象的实例值 student.setScore(90); System.out.println(newUser.toString()); }}
输出:
User(id=1, name=zhangSan, age=25, student=Student(id=1, score=80))User(id=1, name=zhangSan, age=25, student=Student(id=1, score=80))
原user对象中student引用的实例值改变了,拷贝后的对象中引用的实例值没有变,说明它们两个不是同一个引用。
4,序列化拷贝
在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝),写到一个流里,再从流里读出来,便可以重建对象。
@Data@NoArgsConstructor@AllArgsConstructorpublic class Student implements Serializable { private Integer id; private Integer score;}
@Data@AllArgsConstructor@NoArgsConstructorpublic class User implements Serializable { private Integer id; private String name; private Integer age; private Student student;}
public class CopyTest { public static void main(String[] args) throws IOException, ClassNotFoundException { Student student = new Student(1, 80); User user = new User(1, "zhangSan", 25, student); //ByteArrayOutputStream: 可以捕获内存缓冲区的数据,转换成字节数组。 //ByteArrayInputStream: 可以将字节数组转化为输入流 ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(bo); objectOutputStream.writeObject(user);//将user对象,以字节数组的形式写入到内层缓冲区中 ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream objectInputStream = new ObjectInputStream(bi); User newUser = (User) objectInputStream.readObject();//反序列化,生成对象(深拷贝) student.setScore(90); System.out.println(user); System.out.println(newUser); }}
输出:
User(id=1, name=zhangSan, age=25, student=Student(id=1, score=90))User(id=1, name=zhangSan, age=25, student=Student(id=1, score=80))
来源地址:https://blog.csdn.net/weixin_44924882/article/details/128799035
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341