深拷贝和浅拷贝Java

时间:2013-11-12 09:51:36

标签: java arrays shallow-copy

我正在攻读java考试,我发现的实际上与理论教学不同。

以下是代码:

    StringBuilder num3[]= new StringBuilder[2];
    num3[0]= new StringBuilder("Pine");
    num3[1]= new StringBuilder("Oak");
    StringBuilder num4[] = new StringBuilder[2];
    System.arraycopy(num3, 0, num4, 0, 2);
    System.out.println(num3[0]==num4[0]);
    System.out.println(num4[0]);
    num3[0] = new StringBuilder("Choc"); 
    System.out.println(num3[0]);
    System.out.println(num4[0]);

输出结果为:

true
Pine
Choc
Pine

真实的陈述表明它是浅拷贝,因为num4 [0]引用num3 [0]的相同对象。但是当我更改num3 [0]时,我预期num4 [0]也会改变。

如果它是一个浅层副本,为什么会这样?

是因为为num3 [0]创建了新对象而num4数组正在引用旧的“Pine”StringBuilder对象吗?

如果是这样,有人能给我一个System.arraycopy的例子吗?这个浅拷贝很明显?

提前致谢, Chrisyopher

5 个答案:

答案 0 :(得分:7)

System.arraycopy之后,两个数组确实是彼此的浅拷贝。也就是说,您有{em>引用的副本到StringBuilder。引用的对象是相同的。

num3:  [ refA, refB ]                        num4: [ refA, refB ]
           |    |                                      |     |
           |    `-------> StringBuilder("Oak") <-------+-----' 
           `------------> StringBuilder("Pine") <------'

但是,您将num3[0]中的引用更改为指向新的StringBuilder

num3:  [ refC, refB ]                        num4: [ refA, refB ]
           |    |                                      |     |
           |    `-------> StringBuilder("Oak") <-------+-----' 
           |              StringBuilder("Pine") <------'
           `------------> StringBuilder("Choc")

基础对象没有改变。你所做的一切都改变了引用它们的内容。


System.arraycopy就像有一个for循环复制数组中的值,除了它对大型数组更有效(因为现代CPU有大量内存复制的特殊指令)。你根本不需要它语义;这只是一次性能优化。

答案 1 :(得分:1)

num3[0]num4[0]是对同一对象的引用,因此当您更改num3[0]时,它只会更改num3[0]指向的位置,而不会更改num4[0] 1}}指向。

System.out.println(num3[0]==num4[0]);

返回true,因为两者都指向同一个对象,但两者都是个体。

如果你做了类似

的事情

num3[0].append("something")然后你会打印num3[0]num4[0]然后两者都会受到影响。

答案 2 :(得分:1)

您没有更改num3 [0],而是将其指向其他内容,即新的StringBuilder对象。 num3 [0]和num4 [0]不再指向同一个对象,因此num4 [0]不会改变。将复制数组引用的值,但如果您修改这些值,则不会影响其他数组。如果您修改它们所指向的对象,而不是引用来修改这些对象,会对它产生什么影响。

num3[0]num4[0]视为指向行李包的两个人。 如果你在背包里添加东西,它们都会指向已经改变的东西。但是,如果您要求num3[0]指向电视,则num4 [0]仍将指向背包。

答案 3 :(得分:1)

  

是因为正在为num3 [0]和旧的创建新对象   “Pine”StringBuilder对象是由num4数组引用的?

完全。

  

如果是这样,有人能给我一个System.arraycopy的例子吗?这个浅拷贝很明显?

我不确定我是否理解这个问题。没有副本,无论是浅的还是深的,都会对你在副本后做什么产生影响。

但请尝试以下方法:

num3[1].append("tree");
println(num4[1]);        // should be "Oaktree"

答案 4 :(得分:0)

在这种情况下,浅表副本只不过是对该对象的新引用。 您有一个对象Pine,其中一个指针存储在int num3中。现在,您创建一个存储在num4中的浅表副本(您创建一个新引用)。您现在有一个带有两个引用的Pine对象。当您将Choc分配给num3时,引用数量会减少1,并且您有效地将num3所持有的引用替换为另一个引用。 Pine从未改变过任何方式。