5

Java supports pass by value (always works on a copy) but when you pass a user defined object then it changes the actual object (kind of pass by reference but no pointer changes), which I understand but why the changeObject2CLEAR method below is actually changing the value of the object ? Instead it has to work on the copy?


import java.util.HashMap;
import java.util.Map;

public class PassBy {

    class CustomBean {
        public CustomBean() {

        }

        private int id;
        private String name;

        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }   

        @Override
        public String toString() {
            return id + ", " + name;
        }
    }

    public Map<Integer, String> changeObject2NULL (Map<Integer, String> m) {
        m = null;
        return m;
    }

    public Map<Integer, String> changeObject2CLEAR (Map<Integer, String> m) {
        m.clear();
        return m;
    }

    public CustomBean changeCustomObject (CustomBean _e) {

        _e.setId(_e.getId() + 1);
        return _e;
    }

    public static void main(String[] args) {

    PassBy passby = new PassBy();

    Map<Integer, String> map = new HashMap<Integer, String>();
    map.put(1, "value");

    CustomBean bean = passby.new CustomBean();
    bean.setId(1);
    bean.setName("arun");

    // Initial Value
    System.out.println(map.toString());
    System.out.println(bean.toString());
    System.out.println("-------------------------");

    // Pass by value works fine
    passby.changeObject2NULL(map);
    passby.changeCustomObject(bean);

    // Custom object value changes since we pass as the object reference but Map remains with actual value
    System.out.println(map.toString());
    System.out.println(bean.toString());
    System.out.println("-------------------------");

    // Testing Pass by value - CANT UNDERSTAND why it changed the object since it has to be pass-by-value and not by ref in this case ??
    // Why setting to null not chainging the value but clear does ?
    passby.changeObject2CLEAR(map);
    System.out.println(map.toString());

    }
}
Paweł Głowacz
  • 2,926
  • 3
  • 18
  • 25
AKS
  • 184
  • 2
  • 18
  • You're passing the *reference* by value. Lots about this on Google. Good question though. – Bathsheba Sep 11 '15 at 13:59
  • 1
    @Arun I have updated my answer to address the refined form of your question – Blake Yarbrough Sep 11 '15 at 14:17
  • In short `changeObject2NULL(Map m)` contains its own *local* variable `m` which happens to be also method parameter. When you use this method like `changeObject2NULL(map)` `m` copies information about which object `map` holds (this address is *value* of `map` variable). So when you call `m.clear()` it invokes `clear` method on same object which `map` holds so you are able to see new state of that object via `map`. When you call `m = null` you simply change which object `m` holds to `null`; this doesn't affect `map` nor object it is referring to. – Pshemo Sep 11 '15 at 14:17

3 Answers3

3

So let me try to help you understand, Java always does pass by value, but I am sure you know that all object instances are actually pointers to those objects. Now when you send an object then you are passing a value of the address of the object. If you do any changes to the object itself (like m.clear()) then it goes to that address, type casts the object and does the operation on it. But if you change the pointer itself, like m = null, then only the copy of the address you are holding is changed.

vishalv2050
  • 813
  • 1
  • 10
  • 18
  • 2
    downvoter, care to comment ? This is correct answer. At-least, not a wrong answer. – Suresh Atta Sep 11 '15 at 14:06
  • As the question is a duplicate, I'm voting across all the answers in both this question and the duplicate. The answers in the duplicate are vastly superior to this one. So IMO, it doesn't add anything useful. If you have something to add, then add the answer to the duplicate. – Bathsheba Sep 11 '15 at 14:08
  • 1
    @Bathsheba While you're of course free to downvote as you please, I find that a good rule of thumb is to downvote when a question is actively wrong or harmful. If it's just not as good as another answer, then I'll upvote the better answer and just leave the less-good answer untouched. In other words, I help the better answers rise to the top, and don't worry about trying to make the less-good answers sink. – yshavit Sep 11 '15 at 14:09
  • 1
    That's a good way to look at things. I've retracted the downvote. – Bathsheba Sep 11 '15 at 14:10
  • David / Bathsheba / LanguidSquid / other respected contributors...Why setting object to null is pass-by-value but clear method is pass-by-ref ? – AKS Sep 11 '15 at 14:10
  • @Arun This is a bit of a shameless plug :) but [this answer](http://stackoverflow.com/a/9224971/1076640) may help you understand the difference between the reference (which is passed by value) and the instance (which is never directly available to you, but only available via the reference). – yshavit Sep 11 '15 at 14:13
  • @Arun "Why setting object to null is pass-by-value but clear method is pass-by-ref" why do you think that `clear` method uses pass-by-ref? `map` and `m` are two separate variable referring to same object. If you call `clear` on any of this variables you affect same object, so changes are visible via both variables. Setting one of them to `null` doesn't affect other variable. In other words, Java is pass-by-value, always (you just need to understand difference between variable, reference and object). – Pshemo Sep 11 '15 at 14:19
1

When you call changeObject2CLEAR

passby.changeObject2CLEAR(map);

you are passing the instance map.

in the method changeObject2CLEAR

public Map<Integer, String> changeObject2CLEAR (Map<Integer, String> m) {
    m.clear();
    return m;
}

you perform .clear() on that same instance map even though in the method it is called m.

As an exercise in understanding notice that the following method will do the same thing.

public void changeObject2CLEAR (Map<Integer, String> m) {
    m.clear();
}

Notice that you don't have to return the Map<Integer, String> m because the map you have access to is the same instance object passed in wherever the method is called.

EDIT: Why does m = null; behave as pass-by-value but m.clear() behave as pass by reference?

When you 'assign' the value null to m you are changing the reference from the previous instance object map to a new memory location that is null.

When you call the .clear() method on the instance object m you are calling the method on the same object that is at the memory location referenced by map, consequently you modify the map object.

Blake Yarbrough
  • 2,286
  • 1
  • 20
  • 36
0

AFAIK Java only does passes by value, but the values are actually references

miau
  • 227
  • 2
  • 9
  • This is true for `Object` instances but not for primitive types – Blake Yarbrough Sep 11 '15 at 14:01
  • Why setting object to null is pass-by-value but clear method is pass-by-ref ? – AKS Sep 11 '15 at 14:05
  • `null` is a reference, so by assigning null, you're changing the reference in the current scope, thereby "losing" the object you were working on, while clear alters the object whose reference you passed into the function – miau Sep 11 '15 at 14:07