Java Pass by Reference

Java pass by reference

Java always passes arguments by value NOT by reference.


Let me explain this through an example:

public class Main
{
public static void main(String[] args)
{
Foo f = new Foo("f");
changeReference(f); // It won't change the reference!
modifyReference(f); // It will modify the object that the reference variable "f" refers to!
}
public static void changeReference(Foo a)
{
Foo b = new Foo("b");
a = b;
}
public static void modifyReference(Foo c)
{
c.setAttribute("c");
}
}

I will explain this in steps:

  1. Declaring a reference named f of type Foo and assign it to a new object of type Foo with an attribute "f".

    Foo f = new Foo("f");

    Sample Image

  2. From the method side, a reference of type Foo with a name a is declared and it's initially assigned to null.

    public static void changeReference(Foo a)

    Sample Image

  3. As you call the method changeReference, the reference a will be assigned to the object which is passed as an argument.

    changeReference(f);

    Sample Image

  4. Declaring a reference named b of type Foo and assign it to a new object of type Foo with an attribute "b".

    Foo b = new Foo("b");

    Sample Image

  5. a = b is re-assigning the reference a NOT f to the object whose its attribute is "b".

    Sample Image


  6. As you call modifyReference(Foo c) method, a reference c is created and assigned to the object with attribute "f".

    Sample Image

  7. c.setAttribute("c"); will change the attribute of the object that reference c points to it, and it's same object that reference f points to it.

    Sample Image

I hope you understand now how passing objects as arguments works in Java :)

How to do the equivalent of pass by reference for primitives in Java

You have several choices. The one that makes the most sense really depends on what you're trying to do.

Choice 1: make toyNumber a public member variable in a class

class MyToy {
public int toyNumber;
}

then pass a reference to a MyToy to your method.

void play(MyToy toy){  
System.out.println("Toy number in play " + toy.toyNumber);
toy.toyNumber++;
System.out.println("Toy number in play after increement " + toy.toyNumber);
}

Choice 2: return the value instead of pass by reference

int play(int toyNumber){  
System.out.println("Toy number in play " + toyNumber);
toyNumber++;
System.out.println("Toy number in play after increement " + toyNumber);
return toyNumber
}

This choice would require a small change to the callsite in main so that it reads, toyNumber = temp.play(toyNumber);.

Choice 3: make it a class or static variable

If the two functions are methods on the same class or class instance, you could convert toyNumber into a class member variable.

Choice 4: Create a single element array of type int and pass that

This is considered a hack, but is sometimes employed to return values from inline class invocations.

void play(int [] toyNumber){  
System.out.println("Toy number in play " + toyNumber[0]);
toyNumber[0]++;
System.out.println("Toy number in play after increement " + toyNumber[0]);
}

What exactly does pass by reference mean?

Sure, different people currently have different definitions of what "pass-by-reference" means. And that is why they disagree on whether something is pass-by-reference or not.

However, whatever definition you use, you must use it consistently across languages. You can't say that one language has pass-by-value, and have the exact same semantics in another language and say that it is pass-by-reference. Pointing out the analogies between languages is the best way to address this dispute, because although people might have strong opinions about the passing modes in particular languages, when you contrast the identical semantics with other languages, it sometimes brings counter-intuitive results that force them to re-think their definition.

  • One predominant view is that Java is pass-by-value only. (Search everywhere on the Internet and you will find this point of view.) This view is that objects are not values, but are always manipulated through references, and thus it is references that are assigned or passed, by value. This view holds that the test of pass-by-reference is whether it is possible to assign to a variable in the calling scope.

If one agrees with this viewpoint, then one must also consider most languages, including as diverse ones as Python, Ruby, OCaml, Scheme, Smalltalk, SML, Go, JavaScript, Objective-C, etc. as pass-by-value only. If any of this strikes you as strange or counterintuitive, I challenge you to point out why you think it is different between the semantics of objects in any of those languages from objects in Java. (I know that the some of these languages may explicitly claim that they are pass-by-reference; but it is irrelevant what they say; a consistent definition must be applied to all languages based on the actual behavior.)

  • If you take the opposing view that objects in Java are pass-by-reference, then you must also consider C as pass-by-reference.

Take your Java example:

class Thing { int x; }
void func(Thing object){ object.x = 42; object = null; }
Thing something = null;
something = new Thing();
func(something);

in C, it would be equivalent to this:

typedef struct { int x; } Thing;
void func(Thing *object){ object->x = 42; object = NULL; }
Thing *something = NULL;
something = malloc(sizeof Thing);
memset(something, 0, sizeof(something));
func(something);
// later:
free(something);

I claim that the above are semantically equivalent; only the syntax is different. The only syntax differences are:

  1. C requires an explicit * to denote a pointer type; Java's reference (pointers to objects) types don't need an explicit *.
  2. C uses -> to access a field through a pointer; Java just uses .
  3. Java uses new to dynamically allocate memory for a new object on the heap; C uses malloc to allocate it, and then we need to initialize the memory.
  4. Java has garbage collection

Note that, importantly,

  1. The syntax for calling the function with the object are the same in both cases: func(something), without needing to do anything like taking address or anything.
  2. In both cases, the object is dynamically-allocated (it may live beyond the scope of the function). And
  3. In both cases, the object = null; inside the function does not affect the calling scope.

So the semantics are the same in both cases, so if you call Java pass-by-reference you must call C pass-by-reference too.

Is Java really passing objects by value?

Java always passes arguments by value, NOT by reference. In your example, you are still passing obj by its value, not the reference itself. Inside your method changeName, you are assigning another (local) reference, obj, to the same object you passed it as an argument. Once you modify that reference, you are modifying the original reference, obj, which is passed as an argument.


EDIT:

Let me explain this through an example:

public class Main
{
public static void main(String[] args)
{
Foo f = new Foo("f");
changeReference(f); // It won't change the reference!
modifyReference(f); // It will change the object that the reference refers to!
}
public static void changeReference(Foo a)
{
Foo b = new Foo("b");
a = b;
}
public static void modifyReference(Foo c)
{
c.setAttribute("c");
}
}

I will explain this in steps:

1- Declaring a reference named f of type Foo and assign it to a new object of type Foo with an attribute "f".

Foo f = new Foo("f");

Sample Image

2- From the method side, a reference of type Foo with a name a is declared and it's initially assigned to null.

public static void changeReference(Foo a)

Sample Image

3- As you call the method changeReference, the reference a will be assigned to the object which is passed as an argument.

changeReference(f);

Sample Image

4- Declaring a reference named b of type Foo and assign it to a new object of type Foo with an attribute "b".

Foo b = new Foo("b");

Sample Image

5- a = b is re-assigning the reference a NOT f to the object whose its attribute is "b".

Sample Image


6- As you call modifyReference(Foo c) method, a reference c is created and assigned to the object with attribute "f".

Sample Image

7- c.setAttribute("c"); will change the attribute of the object that reference c points to it, and it's same object that reference f points to it.

Sample Image

I hope you understand now how passing objects as arguments works in Java :)

How can I simulate pass by reference in Java?

The primary way you can simulate passing a reference is to pass a container that holds the value.

static void makeAThree(Reference<Integer> ref)
{
ref.set(3);
}

public static void main(String[] args)
{
Reference<Integer> myInt = new Reference<>(4);
makeAThree(myInt);
System.out.println(myInt.get());
}

Since in Java, it is references to objects that are passed by value (the object itself is never passed at all), setting ref to 3 in makeAThree changes the same object referred to by myInt in main().

Disclaimer: Reference isn't a class you can just use with out-of-the-box Java. I'm using it here as a placeholder for any other object type. Here's a very simple implementation:

public class Reference<T> {
private T referent;

public Reference(T initialValue) {
referent = initialValue;
}

public void set(T newVal) {
referent = newVal;
}

public T get() {
return referent;
}
}

Edit

That's not to say it's great practice to modify the arguments to your method. Often this would be considered a side-effect. Usually it is best practice to limit the outputs of your method to the return value and this (if the method is an instance method). Modifying an argument is a very "C" way of designing a method and doesn't map well to object-oriented programming.

Can we use pass by reference in java? If No How does java.util.Arrays.sort works?

Arrays are reference types, so the iArr variable holds a reference to an array.

In other words, when you call

Arrays.sort(iArr);

you're passing a reference (by value) to the sort method, which sorts the array that iArr refers to.


From comments:

What does passing a reference (by value) actually mean?

What pass by reference means is that you're basically passing the variable itself to the method. I.e., what ever the method does with the variable affects the variable on the outside. This is never the case in Java. (Try implementing a swap method and you'll see what I mean.) Passing by value means that you pass the value that's stored in the variable. In this case the value is a reference, so it's passing a reference by value.


Re. second update:

Judging from your image, I think you've understood the situation very well, and I think it boils down to terminology.

If we forget about C++ for a while, it's really simple. All you need to keep in mind is that (A) when you invoke method(var) the argument is a copy of whatever var contains, and (B) the content of a non-primitive variable is a reference (a "pointer" if you so like).

Note that in your question you have

int iArr[] = {2, 1, 9, 6, 4};

which is equivalent to

int[] iArr = new int[] { 2, 1, 9, 6, 4 };

so it all checks out: iArr holds a reference and new returns a reference.

When you invoke Arrays.sort(iArr) the content of iArr is passed (i.e. the reference to the array). This is still not pass-by-reference because the value is passed, not the variable itself. If you reassign the formal parameter inside the method to point to some other array, iArr will still point to the original array when the method returns.

If we do think in terms of C++ things tend to be a bit more complicated; C++ notion of reference is slightly different. With a C++ reference you can in fact implement a real swap:

void swap(int &x, int &y)
{
int temp = x;
x = y;
y = temp;
}

I.e. you can pass in "a variable" (as opposed to just the content of a variable). I like to think of this as you're sharing the scope of the variable with the method you're calling. This can't be done in Java.

So with that in mind, I'd say Java reference are much more like C++ pointers, except that they are limited in the sense that you can't dereference using * operator as you can in C++ (you can't do *person in Java, even though person stores what corresponds to a pointer to a person) and you can't get the address of an object using & operator. Also you can't do any pointer arithmetic. You can't for instance do iArr + 3 to get to the fourth element of your array.

Pass object by reference in Java

No, that is not possible in Java.

In Java, all arguments to methods are passed by value. Note that variables of non-primitive type, which are references to objects, are also passed by value: in that case, a reference is passed by value. Note that passing a reference by value is not the same as passing by reference.

Can you pass by reference in Java?

No, Java cannot do this. Java only passes by value. It passes references by value too.



Related Topics



Leave a reply



Submit