2

I am confused by the way arrays work. If I pass an array reference to some method, then that method is able to change the index values previously stored in array. However, if do the same with, say, a wrapper class object then that method is not able to change the value. Here is the code:

public class TestArray {
    public static void main(String[] args) {
        ChangeValues ch=new ChangeValues();
        int intArr[]={1,2,3};
        Integer iWrapper=new Integer(123);
        ch.changeArray(intArr);
        for(int i:intArr){
            System.out.print(i);// o/p: 789
        }
        System.out.println("\n-----------------");
        ch.changeWrapper(iWrapper);
        System.out.println(iWrapper);// o/p: 123
    }
}

class ChangeValues{
    void changeArray(int i[]){
        i[0]=7;
        i[1]=8;
        i[2]=9;
    }
    void changeWrapper(Integer i){
        i=789;
    }
}

output:

789
-----------------
123

Why is it that an array is able to change and not wrapper object. can any one clear away my doubts? thanks.

3
  • I guess you passe the copy of the reference value to the array to changeArray function cuz Java pass by value Commented Jan 22, 2015 at 22:46
  • 1
    An array is no different from any other object. Some objects (such as String) have no writable fields or attributes, others can be modified. An array can be modified. In your code above you're modifying the CONTENTS of the array in changeArray, but overwriting the reference to the Integer object in changeWrapper -- two entirely different things. Commented Jan 22, 2015 at 22:47
  • 1
    It's important to fully comprehend the difference between the thing pointed to and the thing that does the pointing. It takes awhile before that concept is "second nature" and until then you have to think carefully about which is which in situations like this. Commented Jan 22, 2015 at 23:16

5 Answers 5

5

All arguments to Java methods are passed by value. When the argument is of a reference type (as opposed to a primitive type) then the reference is passed by value. Essentially, that means the method receives a copy of the caller's value.

Any reference to a mutable object may be used to modify that object, but that's different from modifying the variable holding the reference. The two change methods you provided are unlike in that way: changeArray() modifies the array object to which its argument refers, but changeWrapper() only assigns a new value to the local variable (initially) containing its argument.

Sign up to request clarification or add additional context in comments.

Comments

2

Because the wrapper objects are immutable. You have to create a new instance, and since you can't modify a caller's reference you can't modify the wrapper instance. You could (if using Java 8) use an Optional, or create your own POJO and pass it (as long as you modify the POJO's reference, then a caller can access it from the POJO). Something like,

class POJO<T> {
    T v;

    public POJO(T v) {
        this.v = v;
    }

    public T getValue() {
        return v;
    }

    public void setValue(T v) {
        this.v = v;
    }

    @Override
    public String toString() {
        return String.valueOf(v);
    }
}

public static void changeIt(POJO<Integer> a) {
    a.setValue(123);
}

public static void main(String args[]) throws Exception {
    POJO<Integer> p = new POJO<>(1);
    System.out.println(p);
    changeIt(p);
    System.out.println(p);
}

Output is

1
123

2 Comments

Wrapper objects are immutable, but that's not why the two methods presented in the question differ in behavior.
@JohnBollinger Correct, it's because you can't modify the caller's reference (and you can't update the value directly because it is immutable).
1

Instead of using the Integer wrapper, use something like this (note that auto-boxing will be broken, so it will have to be done manually):

public class MyInteger {
    private int intValue;
    public MyInteger(int val) {
        intValue = val;
    }
    public void setValue(int val) {
        intValue = val;
    }
    pubic int intValue() {
        return intValue;
    }
}

Then your changeWrapper method can be:

void changeWrapper(MyInteger i){
    i.setValue(789);
}

And

    ch.changeWrapper(iWrapper);
    System.out.println(iWrapper.intValue());

Will print "789".

Alternatively, you could make intValue public:

public int intValue;

And then your changeWrapper method could become:

void changeWrapper(MyInteger i){
    i.intValue = 789;
}

This is effectively what an array is -- an object with a whole bunch of public fields.

4 Comments

thanks for the code. yeah its working now. so you mean to say that Wrappers are immutable..
@JSK - Any object with no methods to modify it (and no exposed fields) is effectively immutable.
@JSK so you mean to say that Wrappers are immutable I, in fact, did say that (in the first sentence of my answer).
@ElliottFrisch , actually when Hot Licks told something 'bout setter methods, then only I realized the case. yes, bro you were also right.
1

The changeArray method gets a copy of the reference to the array object. Now, both its i and intArr from main refer to the same object. The array access assignment ensures that the element in the referred array is updated. There is only one array, and it gets modified. No reference variables are updated to refer to other objects.

The changeWrapper method gets a copy of the reference to the Integer object. Now, both its i and iWrapper from main refer to the same object. But this is not array access. Saying i = here changes the reference to another reference, the auto-boxed Integer 789. The original reference iWrapper in main is not updated, so it still refers to the original Integer 123, explaining the output.

3 Comments

is it ok to say the pass the copy of reference value of the reference to the array?
If you said i = something; in changeArray that likewise would have no effect, since modifying a parameter in a method does not change the value passed to the method.
@KickButtowski Do you mean a wrapper object, with a reference to an array? You could do that, if you want to have a changeArrayWrapper method re-assign the entire array reference to another array object.
0

Because when you pass a primitive as a parameter (Second case) you are taking a COPY of the primitive to be used for the method. However, when you use a non primitive or reference data type as a parameter (Your array), the argument is SHARED to be used for your method so whatever you do with this object will affect the original object.

You can find a better explanation of this here in the section "Passing parameters": http://pages.cs.wisc.edu/~bahls/cs302/PrimitiveVsReference.html

PD: Sorry for my English, it's so bad.

1 Comment

no @robert08 it is not because of copy or sharing. Wrapper is a case of immutable object. If I replace the wrapper integer with any thing like dog or cat and give them a setter method then it will also start behaving like arrays object.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.