【问题标题】:In Java, are fields of array type deep copied or shallow copied?在Java中,数组类型的字段是深复制还是浅复制?
【发布时间】:2014-08-21 00:33:33
【问题描述】:

[背景说明:我是一名具有 C++ 背景的新 Java 程序员,所以对 Java 中如何传递参数有点困惑。]

在阅读和编写一些代码时,我来到了以下案例

public class B{
    int[] intArr;
    Vector<String> strVec;

    void mutator(){
        // modifies intArr and strVec
    }
}

public class A{
    B bOfA;

    A(B b){
        bOfA = b;
    }

    void foo(){
        bofA.mutator();
    }
}
A 中的

foo() 肯定会修改 bOfA,但是传入的对象 b 呢?它的字段/数据成员也会被修改吗?

字段是浅拷贝还是深拷贝?

strVec 和 intArr 的处理方式不同吗,因为 strVec 是一个容器,而 inArr 是一个数组,它可能被实现为某种指针,因此根据它是浅复制还是深复制,行为会完全不同。

谢谢。

使用真实代码进行的(后期)更新,有些令人惊讶(我假设以 C/C++ 方式解释的按值传递机制)结果:

import java.util.Vector;

public class B{
    int[] intArr = null;
    Vector<String> strVec = null;
    int x = 0;
    String s = null;

    B(int sz){

        x = 0;
        s = new String("ini");

        intArr = new int[sz];
        strVec = new Vector<String>(sz);

        for (int i=0; i<sz; i++){
            intArr[i] = 0;
            strVec.add( new String("xx") );
        }
    }

    void mutator(){

        x = -1;
        s = new String("mute");

        int sz = intArr.length;
        strVec = new Vector<String>(sz);

        for (int i=0; i<sz; i++){
            intArr[i] = -1;
            strVec.add( new String("aa") );
        }
    }
}


import java.util.Vector;

public class A{

    B bOfA=null;

    A(B b){
        bOfA = b;
    }

    void foo(){
        bOfA.mutator();
    }
}



import java.util.Vector;

public class C{

    public static void main(String[] args){
        B b = new B(3);

        A a = new A(b);

        System.out.println("Contents of B before:");
        System.out.println(b.x);
        System.out.println(b.s);
        for(int i=0; i<3; i++){
            System.out.println(b.intArr[i]);
            System.out.println(b.strVec.elementAt(i));
        }

        a.foo();

        System.out.println("\n\nContents of A:");
        System.out.println(a.bOfA.x);
        System.out.println(a.bOfA.s);
        for(int i=0; i<3; i++){
            System.out.println(a.bOfA.intArr[i]);
            System.out.println(a.bOfA.strVec.elementAt(i));
        }
        System.out.println("\n\nContents of B after:");
        System.out.println(b.x);
            System.out.println(b.s);
        for(int i=0; i<3; i++){
            System.out.println(b.intArr[i]);
            System.out.println(b.strVec.elementAt(i));
        }
    }

}

以及 cygwin 的结果:

Contents of B before:
0
ini
0
xx
0
xx
0
xx


Contents of A:
-1
mute
-1
aa
-1
aa
-1
aa


Contents of B after:
-1
mute
-1
aa
-1
aa
-1
aa

【问题讨论】:

    标签: java arrays deep-copy shallow-copy


    【解决方案1】:

    Java 通过值传递一切。但是,Object(s) 的值是引用。

    两者数组和向量都是浅拷贝。

    【讨论】:

    • 我们如何在 Java 中进行深拷贝?
    • @KickButtowski 好吧,您可以使用Arrays.copyOf() 方法之一。要获得 Object 的深层副本,您需要为其正确实现 clone()(或新的构造函数,或其他复制方法)。
    • 用户 Arrays.copyOf() 有深拷贝,我也必须覆盖 colne() 吗?
    • @KickButtowski 你想要什么深层副本?
    【解决方案2】:

    数组是引用对象。当您分配它们时,它们根本不会被复制 - 发生的情况类似于将数组分配给 C++ 中的指针。

    当您使用System.arraycopy 复制数组时,会执行浅拷贝。从另一个集合构造一个集合也会创建一个浅拷贝。

    注意:与 C++ 库不同,Java 类库大量使用不可变 类。例如,String 是不可变的;数字的包装器也是如此,例如Integer。不变性使得浅拷贝与深拷贝的相关性大大降低。

    另外注意:Vector&lt;T&gt;在需要同步容器时使用;如果您不想同步,请改用ArrayList&lt;T&gt;

    【讨论】:

    • 我们如何进行深拷贝?
    • @KickButtowski 一种方法是序列化和反序列化对象(这里是an example)。
    【解决方案3】:
    what about b, the object that is passed in? 
    Will its fields/data members be modified as well?
    

    由于默认情况下 java 是按值传递的,因此在构造函数中传递的对象是按值传递的,但在其内部,该对象中的字段将具有引用,因此当您调用 bofA.mutator() 时,B b字段也会改变。

    要进行深层复制,您需要复制传递的 b 对象中的每个字段并使用 Arrays.copyOf()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-11
      • 2014-11-18
      • 2012-06-30
      • 2012-12-11
      • 2014-10-15
      • 2019-05-23
      相关资源
      最近更新 更多