8

Suppose I have this in C++:

void test(int &i, int &j)
{
    ++i;
    ++j;
}

The values are altered inside the function and then used outside. How could I write a code that does the same in Java? I imagine I could return a class that encapsulates both values, but that seems really cumbersome.

  • 1
    Java only passes around object-references. You can think of them essentially the same as boost shared_ptr's. Just box the primitive in an object and you're set. You may want to correct the wording of your question. – Mark Kegel Jan 10 '09 at 04:09
  • 1
    Sorry, but I have to chime in. Pass by reference out parameters in c++ are evil. Don't do it. – Steve Lacey Jan 23 '09 at 07:35
  • @Steve Lacey - why are they evil? – Eric M Sep 01 '09 at 16:31

11 Answers11

22

Simulating reference with wrappers.

One way you can have this behavior somehow simulated is create a generic wrapper.

public class _<E> {
    E ref;
    public _( E e ){
        ref = e;
    }
    public E g() { return ref; }
    public void s( E e ){ this.ref = e; }

    public String toString() {
        return ref.toString();
    }
}

I'm not too convinced about the value of this code, by I couldn't help it, I had to code it :)

So here it is.

The sample usage:

public class Test {

    public static void main ( String [] args ) {
        _<Integer> iByRef = new _<Integer>( 1 );
        addOne( iByRef );
        System.out.println( iByRef ); // prints 2

        _<String> sByRef = new _<String>( "Hola" );
        reverse( sByRef ); 
        System.out.println( sByRef ); // prints aloH

    }

    // Change the value of ref by adding 1
    public static void addOne( _<Integer> ref ) { 
        int i = ref.g();
        ref.s( ++i  );

        // or 
        //int i = ref.g();
        //ref.s( i + 1 );

    }
    // Reverse the vale of a string.
    public static void reverse( _<String> otherRef ) { 
        String v = otherRef.g();
        String reversed = new StringBuilder( v ).reverse().toString();
        otherRef.s( reversed );
    }

}

The amusing thing here, is the generic wrapper class name is "_" which is a valid class identifier. So a declaration reads:

For an integer:

_<Integer> iByRef = new _<Integer>( 1 );

For a String:

_<String> sByRef = new _<String>( "Hola" );

For any other class

_<Employee> employee = new _<Employee>( Employee.byId(123) );

The methods "s" and "g" stands for set and get :P

OscarRyz
  • 196,001
  • 113
  • 385
  • 569
14

Java has no equivalent of C++ references. The only way to get this to work is to encapsulate the values in another class and swap the values within the class.

Here is a lengthy discussion on the issue: https://jonskeet.uk/java/passing.html

N3pp
  • 33
  • 1
  • 4
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
7

Well, there are a couple of workarounds. You mentioned one yourself. Another one would be:

public void test(int[] values) {
    ++values[0];
    ++values[1];
}

I would go with the custom object, though. It’s a much cleaner way. Also, try to re-arrange your problem so that a single method doesn’t need to return two values.

Bombe
  • 81,643
  • 20
  • 123
  • 127
7

Java does not have pass-by-reference. You must encapsulate to achieve the desired functionality. Jon Skeet has a brief explanation why pass-by-reference was excluded from Java.

jason
  • 236,483
  • 35
  • 423
  • 525
4

A better question: why are you creating methods with such side-effects?

Generally, this is a strong indication that you should extract the data into a separate class, with public accessors that describe why the operation is taking place.

kdgregory
  • 38,754
  • 10
  • 77
  • 102
1

Java passes parameters by value, and has no mechanism to allow pass-by-reference.

0

The easiest solution is to use org.apache.commons.lang.mutable.MutableInt class you don't need to write by yourself.

Marwen Trabelsi
  • 4,167
  • 8
  • 39
  • 80
0

You have to box it (your way) somehow.

Integer is immutable. so useless. int is mutable but since java is pass by value then its unusable again in that case. See these pages for more explanations: Java is Pass-by-Value, Dammit! and int vs Integer

Apache commons lang has a MutableInt class. Or you could write it yourself.

In any case, it should not be that bad because it should not happen often. If it does, then you should definitively change the way you code in Java.

Loki
  • 29,950
  • 9
  • 48
  • 62
0

Are the two integers related? Like a pair of x/y coordinates? If so, I would put the integers in a new class and pass that class into the method.

class A{ 
  public void test(Coord c)
  {
    c.x++;
    c.y++;
  }
  private class Coord{
    public int x, y;
  }
}

If the two integers are not related, you might want to think about why you are passing them into the same method in the first place.

Michael
  • 34,873
  • 17
  • 75
  • 109
0

Though its a bad design pattern IMHO, Another possible solution is

static void test(AtomicInteger i, AtomicInteger j)
{
    i.incrementAndGet();
    j.incrementAndGet();
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
-4

You could construct boxed objects, ie,

Integer iObj = new Integer(i);
Integer jObj = new Integer(j);

and write your routine as

public void test(Integer i, Integer j){
  i = i.add(1);
  j = j.add(1);
}

For any number of reasons, the designers of Java felt call-by-value was better; they purposefully didn't include a method for call by reference. (Strictly, they pass copies of references to the objects, with the special case for the primitive types that they are purely call by value. But the effect is the same.)

jjnguy
  • 136,852
  • 53
  • 295
  • 323
Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • That will still not change the objects outside of the method, as Integers are immutable. – Bombe Jan 10 '09 at 03:23
  • Where did you get the idea that Integer had an add() method? Anyway, as Bombe pointed out, Integers are immutable, which leaves you with the exact same problem (but with more typing). – Alan Moore Jan 10 '09 at 04:06
  • Looks like I should have addressed that comment to jinguy; he's the one who added those methods. – Alan Moore Jan 10 '09 at 04:10
  • you could pass in AtomicInteger instead, that's mutable. That isn't its intended purpose, but would almost make this method work. – John Gardner Jan 10 '09 at 05:12
  • this won't work as object references are passed by value, as everything in java. read this. http://stackoverflow.com/questions/373419/whats-the-difference-between-a-parameter-passed-by-reference-vs-passed-by-value#373429 – Johannes Schaub - litb Jan 10 '09 at 12:57
  • it has nothing todo with whether or not Integer is immutable tho. .. ugg it was jinguy who added those code in test. well ok it *had* something todo with immutability before jinguy changed that answer :p now it solely has todo with pass-by-value instead of pass-by-reference :) – Johannes Schaub - litb Jan 10 '09 at 13:05