views:

813

answers:

7

package myintergertest;

/**
 *
 * @author Engineering
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //this one does not increment 
        Integer n = new Integer(0);
        System.out.println("n=" + n);
        Increment(n);
        System.out.println("n=" + n);
        Increment(n);
        System.out.println("n=" + n);
        Increment(n);
        System.out.println("n=" + n);
        Increment(n);

        //this one will increment
        MyIntegerObj myInt = new MyIntegerObj(1);
        Increment(myInt);
        System.out.println("myint = " + myInt.get());
        Increment(myInt);
        System.out.println("myint = " + myInt.get());
        Increment(myInt);
        System.out.println("myint = " + myInt.get());

    }

    public static void Increment(Integer n) {
        //NO.  this doesn't work because a new reference is being assigned
        //and references are passed by value in java
        n++;
    }

    public static void Increment(MyIntegerObj n) {
        //this works because we're still operating on the same object
        //no new reference was assigned to n here.
        n.plusplus();   //I didn't know how to implement a ++ operator...
    }
}

The result for all of those is n=0. Integer n is an object and therefore passed by reference, so why isn't the increment reflected back in the caller method (main)? I expected output to be n=0 n=1 n=2 etc...

UPDATE: Notice I updated the code example above. If I'm understanding correctly, Jon Skeet answered the question of why myInt would increment and why n does not. It is because n is getting a new reference assigned in the Increment method. But myInt does NOT get assigned a new reference since it's calling a member function.

Does that sound like I understand correctly lol ?

+7  A: 

No, objects aren't passed by references. References are passed by value - there's a big difference. Integer is an immutable type, therefore you can't change the value within the method.

Your n++; statement is effectively

n = Integer.valueOf(n.intValue() + 1);

So, that assigns a different value to the variable n in Increment - but as Java only has pass-by-value, that doesn't affect the value of n in the calling method.

EDIT: To answer your update: that's right. Presumably your "MyIntegerObj" type is mutable, and changes its internal state when you call plusplus(). Oh, and don't bother looking around for how to implement an operator - Java doesn't support user-defined operators.

Jon Skeet
Did you mean to say ' **Objects** are passed by value - ...'?
FrustratedWithFormsDesigner
No, he didn't. Primitives and references are passed by value. Objects are not passed at all; they live on the heap.
danben
I think I understand, see my updates and let me know. thanks!!!
cchampion
You decided not to explain about modifying an `Integer` by reflection then? :-)
finnw
+4  A: 

You are looking for something similar to C++'s reference or to C#' out parameter. Java (and many other languages) does not support this.

This type of behavior is typically achieved by changing the method from void to (in this case) int: public static int increment(int n) { return ++n; }

If the method is already returning something then you can create a new class that has two fields (can even be public): the original return value and the new value of n.

Alternatively, you can also wrap the integer inside a generic Cell class. You only need to write this Cell class once:

public class Cell<T> {
  public Cell(T t) { value = t; }
  public void set(T t) { value = t; }
  public T get() { return value; }
}

You can then use it in all situations where you want to a method to change a primitive:

public static void increment(Cell<Integer> n) {
  n.set(n.get()++);
}

Cell<Integer> n = new Cell<Integer>(0);
increment(n);
increment(n);
increment(n);
System.out.println(n.get()); // Output: 3
Itay
+2  A: 

You could use an AtomicInteger from java.util.concurrent.atomic. It has a 'incrementAndGet' method which is suitable for your showcase.

DerMike
+1  A: 

Integer is a value object which means that is value can't change.

Note that n++ is the equivalent of n = n + 1. You're just changing the value referred to by the local variable n, not the value of n itself.

Kevin
+1  A: 

You can't. Java is strictly pass-by-value.

See http://javadude.com/articles/passbyvalue.htm

Your choices are to wrap the integer in an object (or array), pass that in and update, return a value, or make the integer a class/instance variable.

Which is better depends on the situation.

Joe
+3  A: 

As Jon Skeet mentioned, all methods in Java are pass-by-value, not pass-by-reference. Since reference types are passed by value, what you have inside the function body is a copy of the reference - this copy and the original reference both point to the same value.

However, if you reassign the copy inside the function body, it will have no effect on the rest of your program as that copy will go out of scope when the function exits.

But consider that you don't really need pass-by-reference to do what you want to do. For instance, you don't need a method to increment an Integer - you can just increment it at the point in your code where it needs to be incremented.

For more complex types, like setting some property on an Object, the Object you are working with is likely mutable; in that case a copy of the reference works just fine, since the automatic dereference will get you to the original object whose setter you are calling.

danben
A: 

Side note: In my humble opinion, writing n++ on an Integer object is extremely misleading. This relies on a feature of Java called "autoboxing" where it converts primitives to their corresponding boxing objects -- like int to Integer or boolean to Boolean -- automatically and without warning. Frankly I think it's a bad feature. Yes, sometimes it makes your life simpler by automatically doing a handy conversion for you, but it can also do conversions that you did not intend and do not realize are happening, with unintended side effects.

Anyway, there are two ways to accomplish what you are apparently trying to do:

One: Have the increment function return a new Integer with the updated value. Like:

   public Integer increment(Integer n)
    {
      Integer nPlus=Integer.valueOf(n.intValue()+1);
    }

then call it with:

Integer n=Integer.valueOf(0);
n=increment(n); // now n==1
n=increment(n); // now n==2

Etc.

Two: Create your own class that resembles Integer but that is mutable. Like:

class MutableInteger
{
  int value;
  public MutableInteger(int n)
  {
    value=n;
  }
  public void increment()
  {
    ++value;
  }
  ... whatever other functions you need ...
}

Of course the big catch to this is that you pretty much have to re-invent the Integer class.

Jay