3

我正在为 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 语句表明它是浅拷贝,因为 num4[0] 引用了 num3[0] 的相同对象。但是当我改变 num3[0] 时,我希望 num4[0] 也会改变。

如果它是浅拷贝,为什么会发生这种情况?

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

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

提前致谢, 克里斯约弗

4

5 回答 5

8

之后System.arraycopy,这两个数组确实是彼此的浅拷贝。也就是说,您有一份对 s 的引用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 具有用于批量内存复制的特殊指令)。从语义上讲,您永远不需要它;这只是性能优化。

于 2013-11-12T10:01:17.147 回答
1

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

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

这将返回 true,因为两者都指向同一个对象,但都是单独的。

如果你会做类似的事情

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

于 2013-11-12T09:58:15.970 回答
1

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

num3[0]和想象num4[0]成两个人指着一个背包。如果您在背包中添加东西,它们都会指向已更改的内容。但是,如果您要求num3[0]指向电视,num4[0] 仍将指向背包。

于 2013-11-12T10:00:24.310 回答
1

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

确切地。

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

我不确定我是否理解这个问题。没有复制,无论是浅的还是深的,都不会影响你复制后所做的事情。

但请尝试以下操作:

num3[1].append("tree");
println(num4[1]);        // should be "Oaktree"
于 2013-11-12T10:00:44.840 回答
0

在这种情况下,浅拷贝只不过是对对象的新引用。您有Pine一个指向它的对象存储 int num3。现在你制作一个浅拷贝(你创建一个新的引用),它存储在num4. 您现在拥有一个Pine带有两个引用的对象。当您分配Chocnum3引用数时,引用数减少 1,并且您有效地将所持有的引用替换为num3不同的引用。Pine从未以任何方式改变。

于 2013-11-12T10:01:23.093 回答