关于Arrays.copyOf
是否会产生深层或浅层副本,似乎存在很多混淆和不同意见([1]和其他来源)。
此测试表明副本很深:
String[] sourceArray = new String[] { "Foo" };
String[] targetArray = java.util.Arrays.copyOf( sourceArray, 1 );
sourceArray[0] = "Bar";
assertThat( targetArray[0] ).isEqualTo( "Foo" ); // passes
该测试表明该副本很浅:
String[][] sourceArray = new String[][] { new String[] { "Foo" } };
String[][] targetArray = java.util.Arrays.copyOf( sourceArray, 1 );
sourceArray[0][0] = "Bar";
assertThat( targetArray[0][0] ).isEqualTo( "Foo" ); // fails
解决方案是否只是制作了顶级维度的深层副本,但其他维度是浅层副本?真相是什么?
答案 0 :(得分:23)
它生成一个浅拷贝,即包含“旧”引用的 new 数组(对于相同的对象,不会被复制)。
特别是,如果您有嵌套数组,则不会复制这些数组。您将获得一个新的数组,其“顶级”指向与原始数组相同的“第二级”数组。这些嵌套数组中的任何更改都将反映在副本和原始数据中。
此测试表明副本很深:
不,它没有。将新对象分配给“原始”数组时,这不会影响副本。毕竟,这是一份副本。
这与以下情况相同:
String x = "foo";
String y = x;
x = "bar";
assertEquals(y, "foo");
这里没有“深层复制”。
答案 1 :(得分:4)
答案 2 :(得分:1)
'浅'或者' deep' - 这是我认为没有人精确定义的问题 - 方法Arrays.copyOf(..)
实际上会产生源数组的副本,它不受源数组更改的影响。
对int数组采用以下简单示例:
import java.util.Arrays;
public class DeepCopyTest
{
public static void main(String[] args)
{
int[] source = { 1, 2, 3, 4, 5, 6};
int[] target = new int[source.length];
// Copy target from source via Arrays.copyOf(..) method :
target = Arrays.copyOf(source, 6);
// Check for equality :
System.out.println("Source1 : " + Arrays.toString(source));
System.out.println("Target1 : " + Arrays.toString(target));
// Increment all entries in source array :
for(int i = 0; i < source.length; i++)
{
source[i] = source[i] +1;
}
// See if target is affected :
System.out.println("Source2 : " + Arrays.toString(source));
System.out.println("Target2 : " + Arrays.toString(target));
}
}
// OUTPUT
// ------
Source1 : [1, 2, 3, 4, 5, 6]
Target1 : [1, 2, 3, 4, 5, 6]
Source2 : [2, 3, 4, 5, 6, 7]
Target2 : [1, 2, 3, 4, 5, 6]
在实践中,当人们寻求深层复制时,#34;对于一个数组,他们只想要一些不受原始变化影响的东西。
这个Arrays.copyOf(..)`方法确实给了他们这个。
除了原始类型数组之外,String对象数组的行为与上面的示例相同,输出如下:
Source1 : [a, b, c, d, e, f]
Target1 : [a, b, c, d, e, f]
Source2 : [a1, b1, c1, d1, e1, f1]
Target2 : [a, b, c, d, e, f]
当初始源数组条目由&#34; 1&#34;。
连接时它也可以“工作”。对于Object数组,意味着当重新分配目标时,目标不再与源绑定。 但是在复制之后查看两个数组的第一个元素的输出,然后在更改source [0]之后显示完整的事实:
Source1 : java.lang.Object@1db9742
Target1 : java.lang.Object@1db9742
Source2 : java.lang.Object@106d69c
Target2 : java.lang.Object@1db9742
复制原始源数组后,目标元素只是指向其源对应项中当前保存的任何值。对于目标[0],它是存储器地址1db9742的内容 - 它也是保持源[0]的相同存储器地址。 。 。
在source [0]重新分配之后,我们在源和目标之间得到剥离的原因是由于赋值语句
source[0] = new Object();
只是将源[0]中保存的内存引用更改为某个新位置,因为正在指向新的Object。 因此,它纯粹意义上并不是真正的深层复制,即使在很多情况下它给编码器提供了与深层复制相同的好处。
对于原始数据数组,Arrays.copyOf(..)方法不能复制引用,因为它们不用于基元。它只是将源元素值复制到目标元素中。同样,我们与深度副本具有相同的效果,代价是操作需要的代码少于深度副本。
所以Arrays.copyOf(..)是一个“便宜的”。原始和1-D对象数组的深层复制。 但是任何数据阵列都比较复杂,并且可以找到它。
也许它应该被称为半深拷贝。
答案 3 :(得分:0)
它创建Shallow副本,因为但是由于java使用参数值,所有变量的副本在克隆对象中可用,但是对于引用类型,创建地址变量副本并指向由原始数组引用的同一对象,因此在复制时对象是在数组中修改的原始对象也得到更新。 请参阅下面的代码。
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class ArraysCopyOfDemo
{
public static void main (String[] args) throws java.lang.Exception
{
Object[] originalArray= new Object[1];
Employee e1= new Employee("Salman","Khan");
originalArray[0]=e1;
System.out.println("Original Array content printed ");
printArray(originalArray);
Object[] copiedArray=originalArray.clone();
System.out.println("Copied Array content printed ");
printArray(copiedArray);
System.out.println("Copied Array content modified ");
Employee CopiedEmp1= (Employee)copiedArray[0];
CopiedEmp1.setFirstname("Amir");
System.out.println("Copied Array content printed ");
printArray(copiedArray);
System.out.println("Original Array content printed to verify shallow copy or deep copy");
printArray(originalArray);
}
private static void printArray(Object[] arrays ){
for(Object emp:arrays){
System.out.print(((Employee)emp).getFirstname() + " ");
System.out.print(((Employee)emp).getLastname());
System.out.println();
}
}
}
class Employee implements Cloneable{
private String firstname;
private String lastname;
public Employee(String firstname,String lastname){
this.firstname=firstname;
this.lastname=lastname;
}
public String getFirstname(){
return firstname;
}
public String getLastname(){
return lastname;
}
public void setFirstname(String firstname){
this.firstname=firstname;
}
public void setLirstname(String lastname){
this.lastname=lastname;
}
}
O/p
Original Array content printed
Salman Khan
Copied Array content printed
Salman Khan
Copied Array content modified
Copied Array content printed
Amir Khan
Original Array content printed to verify shallow copy or deep copy
Amir Khan
答案 4 :(得分:-4)
这是一本很深的副本。在字符串的情况下它看起来很浅,因为在封面下,字符串是单身人士。 JVM为字符串提供了一个内存池,并且只为每个唯一字符串创建一个副本。所以你总是得到对该字符串的引用的副本。下面的示例显示了为Object类创建了一个深层副本。更改原始数组后,副本不会更改。
public class ArrayTest {
public static void main(String [] args) {
Object [] objs = new Object[1];
objs[0] = new Object();
System.out.println("Original: " + objs[0].toString());
Object [] copy = java.util.Arrays.copyOf(objs, 1);
objs[0] = new Object();
System.out.println("copy, after original reassigned: " +
copy[0].toString());
System.out.println("Original, after reassigned: " +
objs[0].toString());
}
}