简体   繁体   中英

How passing an Object as argument differs from passing an Array as argument?

I have come across two scenarios.

One in which an array is passed as argument to a method and if it is updated in the called method, it is reflecting in the calling method as well.

But in the second scenario, a String Object is passed as argument. The object is updated in the called method, but it doesn't reflect in the calling method.

I want to understand what is the difference between two, even though in both cases, value (of reference) is passed as argument. Please see below snippets.

Scenario 1:

class Test {
public static void main(String[] args){
int a[] = {3,4,5};
changeValue(a);
System.out.println("Value at Index 1 is "+a[1]);
}
public static void changeValue(int b[]){
b[1] = 9;
}
}

Output:

Value at Index 1 is 9

Here, reference (Memory Address) related to array a is passed to changeValue . Hence, b is just pointing to same address as a does. Hence, whether I say b[1] or a[1] , it is referring to same memory address.

Scenario 2:

public class Test {
public static void main(String[] args){
String value = "abc";
changeValue(value);
System.out.println(value);
}
public static void changeValue(String a){
a = "xyz";
}
}

Output:

abc

If I apply the same logic here, String Object VALUE's reference (Memory Address) is being passed to changeValue, which is recieved by a . Hence, now a should be referring to the same memory location as VALUE does. Therefore, when a="xyz" is executed, it should replace "abc" with "xyz" .

Can someone please point out where my understanding goes wrong? Thanks in advance!!

Java passes all its arguments by value. This means that a copy of the pointer to the String is made, and then passed to the method. The method then makes the pointer point at another object, but the original pointer still points to the same String.

This is not the same thing:

  • in the first example, you pass an array reference as an argument, therefore you correctly expect it to be changed by manipulating the reference directly;
  • in the second example however, you pass an object reference, sure -- but you change the reference itself in the method. Changes to a are not reflected when the method returns.

Consider any object:

public void changeObj(Object o)
{
    o = new Whatever();
}

a new object is created, but it won't change o in the caller. The same happens here.

The difference here is simple, and it is not actually about immutability of strings, as some other answers (now edited or deleted) might have originally implied. In one version (with the string), you have reassigned the reference, and in other version (with the array), you haven't.

 array[0] = foo; // sets an element, no reassignment to variable
 array = new int[] { 1,2,3 }; // assigns new array
 obj = "hey"; // assigns new value

When you reassign the variable , you are not going to observe that change outside of the method. When you change elements of an array without reassigning the array variable, you will observe those changes. When you call a setter on an object without reassigning the actual variable of the object, you will observe those changes. When you overwrite the variable (new array, assigning new value, creating new object, etc.) those changes will go unobserved.

Arguments are passed (or copied) by value. The variable inside the method has the same value as the variable on the outside at the beginning. The variables are not linked, and they are not aliases for one another. They just happen to contain the same value. Once you reassign the value to one of them, that is no longer true! The variable on the outside is not affected by the variable on the inside, or even another local variable. Consider

Foo foo = new Foo();
Foo other = foo;
foo.setBar(1);
int bar = other.getBar(); // gets 1
foo = new Foo(); 
foo.setBar(42); 
int bar2 = other.getBar(); // still gets 1

foo and other only referenced the same object for a time. Once foo was assigned a new object, the variables no longer had anything in common. The same is true for your reassignments to the parameter variable inside your method.

You're doing different things; with the string you set the parameter value, with the array you set something belonging to the reference.

For an equivalent array example you'd need to try setting the array reference to a new array:

public static void changeValue(int[] b) {
    b = new int[] { 42, 60 };
}

The original array won't be changed.

Thank you all for answers and updates..

I understood the difference between scenario 1 and 2 as below..

In scenario 1, the array reference is passed. The called method just updates one of the elements pointed by the reference.

While in scenario 2, the reference is passed, but when the called method assigns "xyz" to the reference variable (pointer), it actually creates a new String Object and its reference is assgined to a local reference variable 'a' (Pointer now points a different objct).

The code in called method is as good as

a = new String("xyz");

Hence, the object in called method and calling method are absolutely different and indepenedent and have no relation with each other.

The same could have happened with scenario 1, if instead of doing

b[1] = 9; 

I would have used

b = new int[] {8,9,10};

I understood, Mutability fundamentals would have come in action, if I might have done like below..

String a="abc";
a="xyz";

In this case, object "abc" was being pointed by 'a'. When 'a' is assigned the duty to point to a new object "xyz", a new object "xyz" is created, which is not replacing the existing object "abc". ie "abc" is still existing but has no reference variable to keep itself accessible anymore. This non-replacement property is because of Immutability of String.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM