Search code examples
javaarraysdeep-copyshallow-copy

In Java, are fields of array type deep copied or shallow copied?


[Background note: I am a new Java programmer with a C++ background, so is a little confused about how arguments are passed around in Java.]

While reading and writing some code, I came to the following case

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();
    }
}

foo() in A definitely modifies bOfA, but what about b, the object that is passed in? Will its fields/data members be modified as well?

Are the fields shallow or deep copied?

Are strVec and intArr treated differently, because strVec is a container and inArr is an array, which might be implemented as some kind of pointers, therefore behave quite differently depending on if it is shallow or deep copied.

Thank you.

A (late) update with real code and somewhat surprising (I was assuming the pass-by-value mechanism interpreted in the C/C++ way) results:

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));
        }
    }

}

And the results by 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

Solution

  • Arrays are reference objects. When you assign them, they are not copied at all - what happens there is similar to assigning an array to a pointer in C++.

    When you copy an array using System.arraycopy, a shallow copy is performed. Constructing a collection from another collection creates a shallow copy as well.

    Note: Unlike C++ libraries, Java class libraries uses immutable classes a lot. For example, String is immutable; so are the wrappers for numbers, such as Integer. Immutability makes the shallow vs. deep copying a lot less relevant.

    Another note: Vector<T> should be used when you need a synchronized container; if you do not want synchronization, use ArrayList<T> instead.