126

This Java code:

public class XYZ {   
    public static void main(){  
        int toyNumber = 5;   
        XYZ temp = new XYZ();  
        temp.play(toyNumber);  
        System.out.println("Toy number in main " + toyNumber);  
    }

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

will output this:

 
Toy number in play 5  
Toy number in play after increement 6  
Toy number in main 5  

In C++ I can pass the toyNumber variable as pass by reference to avoid shadowing i.e. creating a copy of the same variable as below:

void main(){  
    int toyNumber = 5;  
    play(toyNumber);  
    cout << "Toy number in main " << toyNumber << endl;  
}

void play(int &toyNumber){  
    cout << "Toy number in play " << toyNumber << endl;   
    toyNumber++;  
    cout << "Toy number in play after increement " << toyNumber << endl;   
} 

and the C++ output will be this:

Toy number in play 5  
Toy number in play after increement 6  
Toy number in main 6  

My question is - What's the equivalent code in Java to get the same output as the C++ code, given that Java is pass by value rather than pass by reference?

Community
  • 1
  • 1
Student
  • 4,481
  • 8
  • 27
  • 32
  • 26
    This doesn't seem like a duplicate to me - the supposedly duplicate question deals with how java works and what the terms mean, which is education, while this question asks specifically how to get something resembling pass-by-reference behaviour, something many C/C++/D/Ada programmers might be wondering in order to get practical work done, not caring why java is all pass-by-value. – DarenW Oct 18 '11 at 18:58
  • 1
    @DarenW I fully agree - have voted to reopen. Oh, and you have enough reputation to do the same :-) – Duncan Jones Nov 01 '13 at 15:48
  • The discussion around primitives is rather misleading, as the question applies equally to reference values. – shmosel Jun 24 '16 at 03:07
  • *"In C++ I can pass the toyNumber variable as pass by reference to avoid shadowing"* - this is not shadowing because the `toyNumber` variable declared in the `main` method is not in scope in the `play` method. Shadowing in C++ and Java only happens when there is nesting of scopes. See https://en.wikipedia.org/wiki/Variable_shadowing. – Stephen C May 05 '19 at 04:09

8 Answers8

187

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]);   
}
laslowh
  • 8,482
  • 5
  • 34
  • 45
  • 3
    Clear explanation and especially good for providing multiple choices on how to code for the desired effect. Directly helpful for something I'm working on right now! It is nuts that this question was closed. – DarenW Oct 18 '11 at 19:08
  • 1
    Although your choice 1 does do what you are trying to convey, I actually had to go back and double check it. The question asks if you can pass by reference; so really you should have done the printlns in the same scope that the toy passed to the function exists in. The way you have it, the printlns are operated in the same scope as the increment which doesn't really prove the point, of COURSE a local copy printed after an increment will have a different value, however that doesn't mean that the passed reference will. Again though, your example does work, but doesn't prove the point. – zero298 Aug 27 '13 at 19:26
  • No, I think it's correct the way it is. Each function "play()" in my answer above is intended as a drop-in replacement for the original "play()" function, which also printed the value before and after incrementing. The original question has the println() in main that proves pass by reference. – laslowh Sep 09 '13 at 12:58
  • Choice 2 requires further explanation: the call site in main must be changed to `toyNumber = temp.play(toyNumber);` for it to work as desired. – ToolmakerSteve Jul 23 '14 at 03:31
  • 1
    This is extremely ugly and have a hackish feel to it... why something so basic isn't a part of the language? – shinzou Aug 21 '16 at 14:28
  • Is your Choice 1 part of, or same as your Choice 3? Both creates a field for the class. – user3207158 Dec 08 '16 at 17:32
29

Java is not call by reference it is call by value only

But all variables of object type are actually pointers.

So if you use a Mutable Object you will see the behavior you want

public class XYZ {

    public static void main(String[] arg) {
        StringBuilder toyNumber = new StringBuilder("5");
        play(toyNumber);
        System.out.println("Toy number in main " + toyNumber);
    }

    private static void play(StringBuilder toyNumber) {
        System.out.println("Toy number in play " + toyNumber);
        toyNumber.append(" + 1");
        System.out.println("Toy number in play after increement " + toyNumber);
    }
}

Output of this code:

run:
Toy number in play 5
Toy number in play after increement 5 + 1
Toy number in main 5 + 1
BUILD SUCCESSFUL (total time: 0 seconds)

You can see this behavior in Standard libraries too. For example Collections.sort(); Collections.shuffle(); These methods does not return a new list but modifies it's argument object.

    List<Integer> mutableList = new ArrayList<Integer>();

    mutableList.add(1);
    mutableList.add(2);
    mutableList.add(3);
    mutableList.add(4);
    mutableList.add(5);

    System.out.println(mutableList);

    Collections.shuffle(mutableList);

    System.out.println(mutableList);

    Collections.sort(mutableList);

    System.out.println(mutableList);

Output of this code:

run:
[1, 2, 3, 4, 5]
[3, 4, 1, 5, 2]
[1, 2, 3, 4, 5]
BUILD SUCCESSFUL (total time: 0 seconds)
Kerem Baydoğan
  • 10,475
  • 1
  • 43
  • 50
  • 3
    This is not an answer to the question. It would have answered the question, if it suggested making an integer array that contained a single element, and then modifying that element within method `play`; e.g. `mutableList[0] = mutableList[0] + 1;`. As Ernest Friedman-Hill suggests. – ToolmakerSteve Jul 23 '14 at 03:39
  • With non-primitives. Object's value is not a reference. Maybe you wanted to say: "parameter value" is "a reference". References are passed by value. – vlakov Jun 20 '15 at 03:59
  • I am trying to do something similar but in your code, the method `private static void play(StringBuilder toyNumber)` - how do you call it if its for example public static int which is returning an integer? Because I have a method that returns a number but if I dont call it somewhere, it is not in use. – frank17 Nov 15 '15 at 11:36
19

Make a

class PassMeByRef { public int theValue; }

then pass a reference to an instance of it. Note that a method that mutates state through its arguments is best avoided, especially in parallel code.

Ingo
  • 36,037
  • 5
  • 53
  • 100
  • 3
    Downvoted by me. This is wrong on so many levels. Java is pass by value - always. No exceptions. – duffymo Apr 10 '11 at 23:58
  • 17
    @duffymo - Of course you can downvote as you please - but have you considered what the OP asked? He wants to pass and int by reference - and just this is accomplished if I pass by value a reference to an instance of the above. – Ingo Apr 11 '11 at 07:55
  • 8
    @duffymo: Huh? You are mistaken, or else misunderstand the question. This **IS** one of the traditional ways in Java of doing what the OP requests. – ToolmakerSteve Jul 23 '14 at 03:42
  • 6
    @duffymo : Your comment is wrong on so many levels. SO is about providing useful answers and comments, and you just simply downvote a correct answer just because (I guess) it doesn't suit your programming style and philosophy. Could you at least offer a better explanation, or even a better answer to the original question? – paercebal Feb 25 '15 at 14:54
  • Not about my preference. It's a profound, common misunderstanding of Java and how it works. Only one mechanism for passing parameters, and it's by value. In all cases. I gave the correct explanation. You don't understand it. Not my problem. Four years late, I'll point out. The proposed solution just encapsulates an int in a class whose reference is passed by value, as are all Java parameters. – duffymo Feb 25 '15 at 15:35
  • 2
    @duffymo that is exactly what I said: pass a ref by value. How do you think pass by ref is accomplished in languages that slow it? – Ingo Feb 25 '15 at 16:56
  • You aren't passing by reference; you're passing a reference by value, because all parameters are passed by value. Subtle but important. Take it up with James Gosling if you disagree. – duffymo Feb 25 '15 at 20:05
  • 1
    @duffymo How comes you think we disagree, when I say *all the time* that we pass by value. In this case we pass (by value, how else?) a reference. And this is equivalent to passing the integer we can access through that reference "by ref". That's how it is done in any programming language. Only some languages have syntactic sugar for it, others, like Java, don't. (I personally like the Java way more, because it is more explicit.) – Ingo Feb 25 '15 at 23:52
  • wouldn't you have to retrieve the value again after the function call? – Mark Walsh Apr 21 '20 at 19:39
11

For a quick solution, you can use AtomicInteger or any of the atomic variables which will let you change the value inside the method using the inbuilt methods. Here is sample code:

import java.util.concurrent.atomic.AtomicInteger;


public class PrimitivePassByReferenceSample {

    /**
     * @param args
     */
    public static void main(String[] args) {

        AtomicInteger myNumber = new AtomicInteger(0);
        System.out.println("MyNumber before method Call:" + myNumber.get());
        PrimitivePassByReferenceSample temp = new PrimitivePassByReferenceSample() ;
        temp.changeMyNumber(myNumber);
        System.out.println("MyNumber After method Call:" + myNumber.get());


    }

     void changeMyNumber(AtomicInteger myNumber) {
        myNumber.getAndSet(100);

    }

}

Output:

MyNumber before method Call:0

MyNumber After method Call:100
Lucas Zamboulis
  • 2,494
  • 5
  • 24
  • 27
premSiva
  • 111
  • 1
  • 5
  • 1
    I use and like this solution because it offers nice compound actions and is easier to integrate into concurrent programs that already or may want to use these atomic classes in the future. – randers Jan 31 '16 at 18:19
11

You cannot pass primitives by reference in Java. All variables of object type are actually pointers, of course, but we call them "references", and they are also always passed by value.

In a situation where you really need to pass a primitive by reference, what people will do sometimes is declare the parameter as an array of primitive type, and then pass a single-element array as the argument. So you pass a reference int[1], and in the method, you can change the contents of the array.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
  • 1
    No -- all the wrapper classes are *immutable* -- they represent a fixed value that can't be changed once the object is created. – Ernest Friedman-Hill Apr 10 '11 at 21:28
  • 1
    "You cannot pass primitives by reference in Java": the OP seems to understand this, as they are contrasting C++ (where you can) with Java. – Raedwald Apr 30 '14 at 12:19
  • 1
    It should be noted that "all the wrapper classes are immutable" said by Ernest applies to JDK's build-in Integer, Double, Long, etc. You can bypass this restriction with your custom wrapper class, like what Ingo's Answer did. – user3207158 Oct 10 '19 at 21:22
  • @Ernest Friedman-Hill Intended by design, but not correct, easily done by reflection. – Sam Ginrich Apr 05 '22 at 21:02
3
public static void main(String[] args) {
    int[] toyNumber = new int[] {5};
    NewClass temp = new NewClass();
    temp.play(toyNumber);
    System.out.println("Toy number in main " + toyNumber[0]);
}

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]);
}
itun
  • 3,439
  • 12
  • 51
  • 75
0

We set a = 5 in the checkPassByValue but it is not reflected in the value of a. Similarly, when we pass a person we can update the data where the person points to by using Person.setName however if change the person and make it refer to a new Person() in that case that update will not be reflected in the main function

class Person {
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name;

    public Person(String name) {
        this.name = name;
    }

}

public class PassByValueVsReference {
    public static void main(String[] args) {
        int a = 3;
        Person person = new Person("Foo");
        checkPassByValue(a, person);
        System.out.println(a);
        System.out.println(person.getName());
    }

    public static void checkPassByValue(int number, Person person) {
        number = 5;
        person.setName("Foo-updated");
        person = new Person("Foo_new reference");
    }
}

//C++ equivalent of checkPassByValue(int ,Person *);

  • Well, in C++ a reference is equivalent to a de-referenced const pointer, you won't change that pointer, too. – Sam Ginrich Apr 05 '22 at 22:14
  • C++ equivalent of above would be checkPassByValue(int number, Person * person) . but in C++ I can still do checkPassByValue(int &number ,Person & person) checkPassByValue(int number,Person & person) or checkPassByValue(int number,Person person) – swapnil darmora Apr 10 '22 at 15:54
  • No, that's the C-equivalent with ´*person´ as reference. – Sam Ginrich Apr 10 '22 at 18:18
  • Why? here in checkPassByValue, we have a number that is passed as a value and also the person is a reference that is also passed by value. For C++ checkPassByValue(int number, Person * person) here also number is passed by value and person is a reference to some Person and also if I do person = person2 it doesn't change the object that person is currently pointing to. Also if I want to make change to object that person is pointing to I would simply do person->setName(val) in C++ and in java person.setName(val) how are these two different ? – swapnil darmora Apr 13 '22 at 20:02
  • ´person = person2´ not a reference. – Sam Ginrich Apr 13 '22 at 21:40
  • Person * person1 = new Person(); Person * person2 = new Person(); if I do person1 = person2; woudn't person 1 point to where person2 is pointing to? Here person1 is a reference right? What I am trying to say is that if Person* person (is a pointer to some Person) and I do person = person2 the local copy of person(reference) changes to where person2 is pointing to but the actual Person* passed from outside will remain same – swapnil darmora Apr 14 '22 at 13:13
  • How would you pass the reference of an object allocated on a heap to a function in c++ without using a pointer? – swapnil darmora Apr 14 '22 at 13:18
  • My comment is that void checkPassByValue(int number, Person person) in Java is equivalent to checkPassByValue(Int number, Person * person) where the person is a reference to some Person object on the heap. If I am wrong can you at least tell me the C++ equivalent of it? – swapnil darmora Apr 14 '22 at 13:27
  • Reference in C++ is ´Person& r;´ as variable and parameter, pointer is ´Person* ptr;´ reference again is ´r = *ptr;´, latter one can serve as reference in C. Java and C are islands in considering references / pointers as value; this thinking was introduced long after the terms ´reference´ and ´value´ as used in Pascal, Delphi, Fortran or C++, where ´by reference´ is a synonym of ´sharing an instance´. – Sam Ginrich Apr 15 '22 at 06:54
  • What I wanted to say was that the C++ equivalent of checkPassByValue(int number, Person person) is checkPassByValue(int number, Person *person) is it incorrect? Also, I understand that in C++ pointers and references are different. So what you are saying is that in C++ foo(int a, Person & person) person is passed as reference whereas in foo(int a, Person *person) a pointer is passed as a value which is the java equivalent – swapnil darmora Apr 15 '22 at 16:50
  • Also in Java, I don't think there is any way to mimic foo(T &). In java primitives are simply passed as foo(T) (c++ equivalent) and anything instantiated with new is passed as foot(T *) // c++ equivalent. – swapnil darmora Apr 15 '22 at 17:19
  • this is not the major task; in C++ for T a class, on an assignment to T&, the built-in assign operator would not replace the T-instance, but map all members; for Java you need to define an assignment method explicitly, to reach this. For simple types as int you would pass a wrapper or an int[] with length 1. The language-defined Wrapper Integer is immutable by design, you can define an own one or mute the given Integer with reflection. – Sam Ginrich Apr 15 '22 at 17:53
  • 1
    I have started working in Java recently so still trying to get the hang of it. I did come with up passing an int[] = new int[1] for this but doesn't look as elegant as C++. Passing a wrapper still feels like a cleaner way to implement that. – swapnil darmora Apr 16 '22 at 05:54
  • Well, the primary philosophy on Java does not support out-values: You rather have in-values and return-values, e.g. return some Object[], which mirrors in-values. I normally help myself with a generic adapter ... public class ByRef { T v; public ByRef(T v) { this.v = v; } public ByRef() { v = null; } public void set(T nv) { v = nv; } public T get() { return v; } } – Sam Ginrich Apr 28 '22 at 12:41
0

"Pass-by..." is reserved in Java and C. Beyond this, if you intend to change a wrapper instance of a primitive given as reference, this is done by reflection. Example for Integer.

public class WrapperTest
{
    static void mute(Integer a)
    {
        try
        {
            Field fValue = a.getClass().getDeclaredField("value");
            fValue.setAccessible(true);
            fValue.set(a, 6);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)
    {
        Integer z = 5;
        mute(z);
        System.out.println(z);
    }

}

Output is 6 as in your C++ example. Reflection is required, because Java design considers primitive wrappers as immutable. Else every other class can serve as wrapper, even an array like int[] of length 1 .

Sam Ginrich
  • 661
  • 6
  • 7