什么是浅拷贝和深拷贝?

x33g5p2x  于2022-02-19 转载在 其他  
字(2.6k)|赞(0)|评价(0)|浏览(435)

在Java语言中,当我们需要拷贝一个Java对象的时候,常见的会有两种方式的拷贝:浅拷贝与深拷贝。

  • 浅拷贝:只是拷贝了源对象的地址,所以源对象的任何值发生改变时,拷贝对象的值也会随之而发生变化。
  • 深拷贝:则是拷贝了源对象的所有值而不是地址,所以即使源对象的值发生任何变化时,拷贝对象的值也不会改变。

1、什么是浅拷贝?

浅拷贝代码演示(最常见的方式):

  1. /**
  2. * 浅拷贝:拷贝的就是目标对象在堆内存中的地址
  3. * 注意:拷贝对象改变,源对象(目标对象)改变
  4. */
  5. public class SlowCopy {
  6. public static void main(String[] args) {
  7. User user = new User();
  8. user.setUserName("张三");
  9. user.setPassWord("123456");
  10. //浅拷贝
  11. User user1 = user ;
  12. System.out.println(user); //com.sqx.copy.bean.User@1b6d3586
  13. System.out.println(user1); //com.sqx.copy.bean.User@1b6d3586
  14. }
  15. }

2、什么是深拷贝?

深拷贝的对象修改的时候,源对象是不受影响的!

2.1、常见的深拷贝方式

一般常用的深拷贝方式有如下5种

1、构造函数方式

  1. /**
  2. * 构造器实现深拷贝 :我们拷贝对象和源对象是隔离的,互不干扰!
  3. */
  4. public class DeepCopy {
  5. public static void main(String[] args) {
  6. //深拷贝
  7. User user = new User("张三","123456");
  8. User user1 = new User("李四","654321");
  9. System.out.println(user); //com.sqx.copy.bean.User@1b6d3586
  10. System.out.println(user1); //com.sqx.copy.bean.User@4554617c
  11. }
  12. }

2、重写Clone方法

1、实现Cloneable接口,Cloneable其实就是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类

调用clone方法才能克隆成功,如果不实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常。

  1. public class Student implements Cloneable {
  2. private String userName ;
  3. private String passWord ; // 此处省略set\get方法
  4. @Override
  5. public Student clone() throws CloneNotSupportedException {
  6. return (Student) super.clone();
  7. }
  8. }

2、代码演示深拷贝

  1. /**
  2. * 重写clone方法实现深拷贝
  3. */
  4. public class DeepCopy01 {
  5. public static void main(String[] args) {
  6. Student student01 = new Student("张三","123456");
  7. Student student02 = null;
  8. try {
  9. student02 = student01.clone(); // 深拷贝对象
  10. } catch (CloneNotSupportedException e) {
  11. e.printStackTrace();
  12. }
  13. System.out.println(student01); //com.sqx.copy.bean.Student@1b6d3586
  14. System.out.println(student02); //com.sqx.copy.bean.Student@4554617c
  15. System.out.println(student01.equals(student02)); // true 标识内容相同,但是仅地址不同(记得重写equlas)
  16. }
  17. }

我们发现拷贝的student02对象和源对象地址已经不同了,但是内容是一致的~

补充

我们的ArrayList 、LinkedList等都实现了Cloneable接口,支持深拷贝

  1. public class ArrayList<E> extends AbstractList<E>
  2. implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
  3. ...
  4. }

样例演示:

  1. public class ArrayListCopyTest {
  2. public static void main(String[] args) {
  3. ArrayList<User> list = new ArrayList<>();
  4. User user = new User("张三", "123456");
  5. list.add(user) ;
  6. System.out.println("list: "+list); //源ArrayList对象
  7. ArrayList<User> clone = (ArrayList<User>) list.clone();
  8. System.out.println("clone: "+clone); //经过深拷贝得到的ArrayList对象
  9. System.out.println(list == clone); // false 经过深拷贝,创建的是新的对象
  10. System.out.println(list.get(0) == clone.get(0)); //true 说明拷贝对象和源对象的内容是一样的!
  11. }
  12. }

总结:

  • 浅拷贝只复制某个对象的引用,而不复制对象本身,新旧对象还是共享同一块内存
  • 深拷贝会创造一个一摸一样的对象,新对象和原对象不共享内存,修改新对象不会改变原对对象

实现深拷贝的方式还有:Apache Commons Lang序列化、Gson序列化、jackson序列化等

相关文章