什么是浅拷贝和深拷贝?

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

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

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

1、什么是浅拷贝?

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

/**
 *  浅拷贝:拷贝的就是目标对象在堆内存中的地址
 *         注意:拷贝对象改变,源对象(目标对象)改变
 */
public class SlowCopy {
    public static void main(String[] args) {
        User user = new User();
        user.setUserName("张三");
        user.setPassWord("123456");
        //浅拷贝
        User user1 = user ;

        System.out.println(user); //com.sqx.copy.bean.User@1b6d3586
        System.out.println(user1); //com.sqx.copy.bean.User@1b6d3586
    }
}

2、什么是深拷贝?

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

2.1、常见的深拷贝方式

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

1、构造函数方式

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

2、重写Clone方法

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

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

public class Student implements Cloneable {

    private String userName ;

    private String passWord ;   // 此处省略set\get方法 

    @Override
    public Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }
}

2、代码演示深拷贝

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

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

补充

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

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

样例演示:

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

总结:

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

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

相关文章