Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my current object modified when I use an instance method to return another object? - Java

I have this class and I don't understand what exactly is going on:

public class Table {
    private int[][] array;
    private int N;

    // constructor
    public Table(int[][] array) {
        N = array.length;
        this.array = Arrays.copyOf(array, N);
    }

    // this method returns another Table object
    public Table tweak() {
        int[][] tweak = Arrays.copyOf(array, N);
        // here I change the array
        return new Table(tweak);
    }
}

The problem is when I call the tweak method, the object used to call the method changes also:

public class TestCls {
    public static void main(String[] args) {
        int[][] array = {{1, 2}, 
                         {3, 4}};
        Table a = new Table(array);
        System.out.println(a.toString());
        /* this will print
        *  1  2 
        *  3  4
        */

        Table b = a.tweak();
        System.out.println(b.toString());
        /* this will print
        *  2  1 
        *  3  4
        */

        System.out.println(a.toString());
        /* this will also print
        *  2  1 
        *  3  4
        */
    }
}

Please help me understand why is this happening and how should I change the tweak method so that the original object is not changed.

Thanks

like image 309
flo Avatar asked May 07 '26 08:05

flo


2 Answers

Arrays.copyOf is creating a new int[][], but that takes a shallow copy - it's equivalent to:

int[][] tweak = new int[array.length][];
for (int i = 0; i < tweak.length; i++) {
    tweak[i] = array[i];
}

So while you've got a new "top level" array, each "subarray" is shared. You really want to make a deep copy of the array:

int[][] tweak = new int[array.length][];
for (int i = 0; i < tweak.length; i++) {
    tweak[i] = array[i].clone(); // Simpler way of performing a shallow copy
}

That's performing a shallow copy of each "subarray", but that's fine because the element type is just int (there's no way to make it "deeper").

Note that you only need to this either in the tweak method or in the constructor. There's no point in making two copies.

like image 89
Jon Skeet Avatar answered May 09 '26 21:05

Jon Skeet


The issue is that the Table constructor makes a shallow copy of the array.

See How do I do a deep copy of a 2d array in Java?

like image 23
NPE Avatar answered May 09 '26 22:05

NPE



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!