Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2019-06-13:Java 中深拷贝与浅拷贝的区别? #75

Open
Moosphan opened this issue Jun 13, 2019 · 14 comments
Open

2019-06-13:Java 中深拷贝与浅拷贝的区别? #75

Moosphan opened this issue Jun 13, 2019 · 14 comments
Labels

Comments

@Moosphan
Copy link
Owner

No description provided.

@Moosphan Moosphan added the Java label Jun 13, 2019
@424385117
Copy link

深拷贝是创建一个新的对象然后赋值相同的值,浅拷贝是引用指向同一个对象

@whatshappen
Copy link

深拷贝是址拷贝,浅拷贝是值拷贝

@424385117
Copy link

深拷贝是址拷贝,浅拷贝是值拷贝

你说反了吧

@Petterpx
Copy link

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址。因此如果其中一个对象改变了地址,就会影响到另一个对象。
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢而且花销大。
如何选择:
如果对象的属性全是基本类型的,那么可以使用浅拷贝,但是如果对象有引用属性,那就要基于具体的需求来选择浅拷贝还是深拷贝。我的意思是如果对象引用任何时候都不会被改变,那么没必要使用深拷贝,只需要使用浅拷贝就行了。如果对象引用经常改变,那么就要使用深拷贝。没有一成不变的规则,一切都取决于具体需求。

@zhaoerlei1989
Copy link

首先需要明白,浅拷贝和深拷贝都是针对一个已有对象的操作。那先来看看浅拷贝和深拷贝的概念。在 Java 中,除了基本数据类型(元类型)之外,还存在 类的实例对象 这个引用数据类型。而一般使用 『 = 』号做赋值操作的时候。对于基本数据类型,实际上是拷贝的它的值,但是对于对象而言,其实赋值的只是这个对象的引用,将原对象的引用传递过去,他们实际上还是指向的同一个对象。而浅拷贝和深拷贝就是在这个基础之上做的区分,如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有真实的创建一个新的对象,则认为是浅拷贝。反之,在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量,则认为是深拷贝。所以到现在,就应该了解了,所谓的浅拷贝和深拷贝,只是在拷贝对象的时候,对 类的实例对象 这种引用数据类型的不同操作而已。总结来说:1、浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。2、深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

@gabyallen
Copy link

在Java中浅拷贝和深拷贝就是在这个基础之上做的区分,如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有真实的创建一个新的对象,则认为是浅拷贝。反之,在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量,则认为是深拷贝。
所以到现在,就应该了解了,所谓的浅拷贝和深拷贝,只是在拷贝对象的时候,对 类的实例对象 这种引用数据类型的不同操作而已。
总结来说:
1、浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。并且它们之间的hashcode不一样,只是其数据类型字段相同。
2. 深拷贝:是对对象,数据类型值and 它们之间的hashcode拷贝;进行对象完完全全的clone();原对象与新对象对比完全相同。

@18361237136
Copy link

无论是拷贝基本数据类型还是引用类型,只要没有创建一个新的对象就成为浅拷贝,如果创建了一个对象并且复制了其内的成员变量成为深拷贝

@yangfanggang
Copy link

看了一会 还是不明白 和头像一样 打卡打卡

@August1993
Copy link

浅拷贝和深拷贝的区别是 如果对象里的成员变量存在引用类型, 当使用浅拷贝时, 新对象的这个属性的地址值和源对象的这个属性一致,即浅拷贝只是对引用类型的地址值拷贝,深拷贝是创建了新的对象,只是属性复制, 浅拷贝的缺点是如果对对象进行多处复制,如果在运行中对其中一个对象的属性进行改变, 那么所有复制的对象都会被改变,不利于管理

@WislieZhu
Copy link

WislieZhu commented Sep 4, 2019

浅拷贝:
1.实现Cloneable
2.成员变量是基本数据类型,也包括String类型

public class ShallowCopy implements Cloneable {
private int age;
private String name;

public ShallowCopy(int age, String name) {
    this.age = age;
    this.name = name;
}

@Override
public Object clone() {
    ShallowCopy s = null;
    try {
        s = (ShallowCopy) super.clone();
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    return s;
}

@Override
public String toString() {
    return "{" +
            "age=" + age +
            ", name='" + name + '\'' +
            '}';
}

public static void main(String[] args) {

    ShallowCopy sample = new ShallowCopy(1, "wislie");

    ShallowCopy cloneObj = (ShallowCopy) sample.clone();

    System.out.println("浅度拷贝 (cloneObj == sample):" + (cloneObj == sample)); //false
    System.out.println("sample:" + sample); //sample:{age=1, name='wislie'}
    System.out.println("cloneObj:" + cloneObj); //cloneObj:{age=1, name='wislie'}
}

}

深拷贝:
有两种实现方式,一种是实现Cloneable,成员变量需要有引用类型的对象;另一种实现了Serializable,对成员变量没有限制.
实现Cloneable的方式:
public class DeepCopy implements Cloneable {

private String value;
private ShallowCopy shaderCopy;

public DeepCopy(String value, ShallowCopy shaderCopy) {
    this.value = value;
    this.shaderCopy = shaderCopy;
}

public String getValue() {
    return value;
}

public void setValue(String value) {
    this.value = value;
}

public ShallowCopy getShaderCopy() {
    return shaderCopy;
}

public void setShaderCopy(ShallowCopy shaderCopy) {
    this.shaderCopy = shaderCopy;
}

@Override
protected Object clone() {
    DeepCopy d = null;
    try {
        d = (DeepCopy) super.clone();
        if(shaderCopy != null){
            d.setShaderCopy((ShallowCopy) shaderCopy.clone());
        }
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    return d;
}

@Override
public String toString() {
    return "{" +
            "value='" + value + '\'' +
            ", shaderCopy=" + shaderCopy +
            '}';
}

public static void main(String[] args) {
    DeepCopy sample = new DeepCopy("high", new ShallowCopy(12, "wislie"));
    DeepCopy cloneObj = (DeepCopy) sample.clone();
    System.out.println("深度拷贝 (cloneObj == sample):" + (cloneObj == sample)); //false
    System.out.println("sample:" + sample); //{value='high', shaderCopy={age=12, name='wislie'}}
    System.out.println("cloneObj:" + cloneObj);//{value='high', shaderCopy={age=12, name='wislie'}}
}

}
实现Serializable的方式
public class DeepCopy2 implements Serializable {

private static final long serialVersionUID = 369285298572961L;  //最好是显式声明ID
private int len;
private Inner inner;

public DeepCopy2(int len, Inner inner) {
    this.len = len;
    this.inner = inner;
}

static class Inner implements Serializable {
    private static final long serialVersionUID = 369285298572941L;  //最好是显式声明ID

    private String color;
    private int alpha;

    public Inner(String color, int alpha) {
        this.color = color;
        this.alpha = alpha;
    }

    @Override
    public String toString() {
        return "Inner{" +
                "color='" + color + '\'' +
                ", alpha=" + alpha +
                '}';
    }
}

@Override
public String toString() {
    return "DeepCopy2{" +
            "len=" + len +
            ", inner=" + inner +
            '}';
}

private DeepCopy2 deepClone() {
    DeepCopy2 data = null;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(this);
        //将流序列化成对象
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        data = (DeepCopy2) ois.readObject();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return data;
}

public static void main(String[] args) {
    DeepCopy2 sample = new DeepCopy2(10, new Inner("blue", 255));
    DeepCopy2 copySample = sample.deepClone();

    System.out.println("sample==copySample:" + (sample == copySample)); //false
    System.out.println("sample:" + sample); //DeepCopy2{len=10, inner=Inner{color='blue', alpha=255}}
    System.out.println("copySample:" + copySample); //DeepCopy2{len=10, inner=Inner{color='blue', alpha=255}}
}

}
不管是浅拷贝还是深拷贝,对象的地址都变了;如果我说的有问题,欢迎指正

@zhufengi
Copy link

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址。因此如果其中一个对象改变了地址,就会影响到另一个对象。
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢而且花销大。
如何选择:
如果对象的属性全是基本类型的,那么可以使用浅拷贝,但是如果对象有引用属性,那就要基于具体的需求来选择浅拷贝还是深拷贝。我的意思是如果对象引用任何时候都不会被改变,那么没必要使用深拷贝,只需要使用浅拷贝就行了。如果对象引用经常改变,那么就要使用深拷贝。没有一成不变的规则,一切都取决于具体需求。

确定会创建一个新对象吗,感觉深拷贝才会创建啊

@loisjee
Copy link

loisjee commented Aug 12, 2020

深拷贝中,如果拷贝的是引用类型,那么会创建一个新的引用类型,并把这个引用类型的地址赋值给新的对象。但是如果这个引用类型指向的对象后续还包括引用类型属性的话,后面会继续深拷贝吗?

@mishaoshuai
Copy link

没有什么问题是一个例子理解不了的
https://blog.csdn.net/qwildwolf/article/details/120138500

@houqingfeng
Copy link

浅拷贝:
java多数场景使用的都是浅拷贝方式,像是集合、函数参数等都是使用的浅拷贝,两个对象指向相同的内存地址,对对象内容操作,所有共同引用的对象都可见。
深拷贝:
需要独立实现,拷贝出来的对象和原对象没有任何关联,两者的操作也互不影响。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests