System.arrayCopy()复制对象或对象的引用?
我有一个最终的类NameAndValue
。 我使用System.arrayCopy()
复制了一个NameAndValue
对象数组,当我在复制的数组中更改了NameAndValue
对象时,它会反映在原始数组中。
public final class NameAndValue { public String name; public String value; public NameAndValue() { } public NameAndValue(String name,String value) { this.name = name; this.value = value; } } public class Main { public static void main(String[] args) { NameAndValue[] nv = new NameAndValue[4]; nv[0] = new NameAndValue("A", "1"); nv[1] = new NameAndValue("B", "2"); nv[2] = new NameAndValue("C", "3"); nv[3] = new NameAndValue("D", "4"); NameAndValue[] nv2 = new NameAndValue[4]; System.arraycopy(nv, 0, nv2, 0, 2); nv2[2] = new NameAndValue("Y","25"); nv2[3] = new NameAndValue("Z","26"); for (int i = 0; i < 2; i++) { NameAndValue[] nv3 = new NameAndValue[4]; System.arraycopy(nv2, 0, nv3, 0, 4); nv3[2].value = String.valueOf(i); nv3[3].value = String.valueOf(i+1); System.out.println(nv2[2].value); System.out.println(nv2[3].value); System.out.println("-----------------------"); } } }
我得到输出,
0 1 ----------------------- 1 2 -----------------------
在所有情况下,我的输出应该是25和26,对吧? 为什么会改变?
System.arrayCopy()复制对象或对象的引用?
参考,这是一个浅层副本。 令人惊讶的是, 文档并没有明确地说 ,只是隐含地说,因为它们只讨论复制数组元素,而不是递归地复制它们引用的东西。
这与你有这个完全相同:
NameAndValue nv1 = new NameAndValue("A", "1"); NameAndValue nv2 = nv1; nv2.value = "4"; System.out.println(nv1.value); // 4
每个数组元素都类似于上面的nv2
和nv2
变量。 正如nv2
和nv2
引用(指向)相同的底层对象一样,数组条目也是如此,包括何时将这些条目从一个数组复制到另一个数组。
它会被更改,因为两个数组仍然引用相同的底层对象。 您可以将新对象分配给数组中的某个位置,但它不会反映在另一个数组中,但如果您对两个数组所指向的对象进行修改,则两者都会以不同方式看到它。
在这个意义上,它通过“按值引用”,而不是通过引用严格传递 – 但您看到的效果是因为引用保持不变。
除非另有明确说明,否则这样的副本几乎总是Java中的浅拷贝。 这也不例外。
据我所知, arraycopy
是一个浅拷贝。 这意味着新数组将引用旧数组中元素的地址。 因此,如果您调整其中一个值,它将反映两者
System.arraycopy是一个浅表副本。 这是为什么:
它使用JNI来使用类似memcpy()的东西,它只是复制内存中的指针。 这是一个非常快速的操作。
int[] a = {1, 2, 3}; int[] b = new int[3]; System.arraycopy(a, 0, b, 0, 3); b[1] = 0; System.out.println(Arrays.toString(b)); System.out.println(Arrays.toString(a));
输出如下:[1,0,3] [1,2,3]