0

The code below indicates that values are being returned by reference:

public class Playground {

    public static void main(String[] args) {
        Map<Integer, vinfo> map = new HashMap<Integer, vinfo>(); 
        map.put(1, new vinfo(true));
        map.put(2, new vinfo(true));
        map.put(3, new vinfo(true));


        for(vinfo v : map.values()){
            v.state = false;
        }

        printMap(map);
    }

    public static void printMap(Map m){
        Iterator it = m.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry pairs = (Map.Entry) it.next();
            Integer n = (Integer) pairs.getKey();
            vinfo v = (vinfo) pairs.getValue();
            System.out.println(n + "=" + v.state);
        }
    }
}

class vinfo{
    boolean state;

    public vinfo(boolean state){
        this.state = state;
    }
}

Output:
1=false
2=false
3=false

In the code below, they are being returned by value. However; I am using the Integer object.

public class Playground {

    public static void main(String[] args) {
        Map<Integer, Integer> map = new HashMap<Integer, Integer>(); 
        map.put(1, 1);
        map.put(2, 1);
        map.put(3, 1);


        for(Integer n : map.values()){
            n+=1;
        }

        printMap(map);
    }

    public static void printMap(Map m){
        Iterator it = m.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry pairs = (Map.Entry) it.next();
            Integer n = (Integer) pairs.getKey();
            Integer n2 = (Integer) pairs.getValue();
            System.out.println(n + "=" + n2);
        }
    }
}

Output:
1=1
2=1
3=1

How can I know when I am directly changing the value (or key for that matter) or I have to do a full .remove() and .put().

keyser
  • 18,829
  • 16
  • 59
  • 101
user2316667
  • 5,444
  • 13
  • 49
  • 71
  • What do you mean by "values" and "returned"? You may be misunderstanding how Java handles objects; objects are always passed (and returned) by reference. In the second example, `getValue()` is returning a reference to an `Integer` object. Also, what do you mean by "directly changing the value"? Any operations you carry out on the result of `get(key)` or `getValue()` are carried out on the actual object whose reference is stored in the `Map`. – chrylis -cautiouslyoptimistic- Aug 01 '13 at 00:38
  • Why do you think your code is showing anything about return by reference vs return by value? Where is your code changing any key and/or value? – Ted Hopp Aug 01 '13 at 00:38
  • Uhm, returning by reference is when you get back the memory location of the actual object, instead of a copy of it. Changes to such a return are therefore reflected in the actual object. So in the first example, we are changing the map's values (proven by changing true to false). In the second, we are adding +1 but nothing changes when you print the map again. – user2316667 Aug 01 '13 at 00:43
  • 1
    @chrylis Hate to be that guy, but in java, _object references_ are [passed by value](http://stackoverflow.com/a/40523/645270). On the bright side, that means that java is pass-by-value only, which is easy to remember. – keyser Aug 01 '13 at 00:43
  • @Keyser Very technically correct (the best kind of correct!), but the difference between passing an object by reference and passing an object reference by value is meaningless in Java (and nearly meaningless in C++). – chrylis -cautiouslyoptimistic- Aug 01 '13 at 00:47
  • @chrylis The second example categorically PROVES that the changes carried out on the objects returned by getValue() IS NOT being carried out on the actual object. We are adding 1 to the value (initially set to 1). So if it had been changed, the map would have printed out 1=2\n2=2\n3=2 – user2316667 Aug 01 '13 at 00:50
  • @user2316667 You're misunderstanding how the Java wrapper types work. Java classes don't have methods like C++'s `operator+` to support operator overloading, so what you have in example 2 is a variable `n` that points to an object of type `Integer`. Java unpacks that to an `int`, adds 1, converts that into another object of type `Integer` (with value 2), and assigns that reference to the variable `n`, which it then throws away. No modification of the object pointed at by the original reference ever occurs, and `Integer` objects are in fact immutable. – chrylis -cautiouslyoptimistic- Aug 01 '13 at 00:51
  • @chrylis Haha yeah, perhaps :). However, didn't my link provide a scenario where it's relevant that it's pass-by-value-of-reference? (overwrite scenarios) – keyser Aug 01 '13 at 00:54
  • @Keyser I don't think so, as noted by izb in the comments there. The two cases of replacing-the-reference-held-by-a-variable (what's happening in example 2) and mutating-the-object-referred-to (what @user2316667 thinks is happening with `+=`) are clearly distinguishable. The example in the link doesn't overwrite `d`, it simply calls a mutator method on it. – chrylis -cautiouslyoptimistic- Aug 01 '13 at 01:01
  • Okay okay okay... this is... I need time to digest this... I really appreciate all the responses. Someone gave this link: http://stackoverflow.com/questions/40480/is-java-pass-by-reference/40523#40523 Either deleted it or I cannot find it. But I really appreciate it. Excellent explanation. – user2316667 Aug 01 '13 at 01:04
  • user2316667, That would be me :p NP. And @chrylis, I'm still not convinced :) erlandos answer to that comment is what caught my eye. – keyser Aug 01 '13 at 01:06

2 Answers2

3

Integers are immutable. You cannot change the value of a particular instance of an Integer once it has been constructed. You can, however, set an Integer variable equal to a different instance of Integer (unless the variable was declared final). Your assignment (+=) is constructing a new Integer object and setting your variable n to reference it.

Your class vinfo is not immutable, and so behaves as you expected.

fred02138
  • 3,323
  • 1
  • 14
  • 17
2

To make a long story short, java objects have some very peculiar properties.

In general, java has primitive types (int, bool, char, double, etc) that are passed directly by value. Then java has objects (everything that derives from java.lang.Object). Objects are actually always handled through a reference (a reference being a pointer that you can't touch). That means that in effect, objects are passed by value, as the references are normally not interesting. It does however mean that you cannot change which object is pointed to as the reference itself is passed by value.

To simplify your problem see the below code

@Test
public void testIntegerValue() {
    Integer num = new Integer(1);
    setInteger(num);
    System.out.println(num); // still return one, why? because Integer will convert to 
                            // int internally and int is primitive in Java, so it's pass by value

}

public void setInteger(Integer i) {
    i +=1;
}
Seabook
  • 137
  • 3