1

Following program output

In second v.i:15
In first v.i:20

why its not 15 in both cases.Object of Value is passed and then object reference is changed in the Second method.Second method its 15 as it should be and seems like in First method it should also be 15

public class Test {
    /**
     * @param args
     */
    class Value{
        public int i = 15;
    }
    public static void main(String[] args) {
        Test t = new Test();
        t.first();
    }
    public void first(){
        Value v = new Value();
        v.i = 25;
        second(v);
        System.out.println("In First v.i:" + v.i);
    }
    public void second(Value v){
        v.i = 20;
        Value val = new Value();
        v = val;
        System.out.println("In second v.i:" + v.i);
    }
}
lfergon
  • 963
  • 15
  • 27
android
  • 570
  • 1
  • 6
  • 13

4 Answers4

3

Java method implementations are call by[reference to, in case of objects,]value but not exactly a call by reference.

You are passing an object Value v means an in-line, method scope variable v is referring to the object v created in method first(). That means any modifications to the same object, referred by v, will also reflect at calling end. But, in your second method, you are creating a fresh object for Value but pointing to the method scope variable v. This new objects memory location is not the same as that of passed in method parameter. To identify the difference, check the hashCode of the objects created using their reference variables.

And hence changing the instance variables of v in method second will not be returned to the caller of the method, unless the method is returning the altered object. Your method returns a void here.

Programmers, most of the time, get confused with the same reference names used in caller and called methods.

Look at the following example to understand the difference. I have included a third' and afourth` methods, to explain it further.

public class Test {
    class Value {
        int i = 15;
    }

    public void second( Value v ) {
        System.out.println( " 2.1.1: entered: v.i = " + v.i ); // 25
        System.out.println( " 2.1.2: v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );

        v = new Value();
        v.i = 9;
        System.out.println( " 2.2.1:   new V: v.i = " + v.i ); // 9
        System.out.println( " 2.2.2: v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
    } // second(v)

    public Value third( Value v ) {
        System.out.println( " 3.1.1:  entered: v.i = " + v.i ); // 25
        System.out.println( " 3.1.2:  v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );

        v = new Value();
        v.i = 9;
        System.out.println( " 3.2.1:  created: v.i = " + v.i ); // 9
        System.out.println( " 3.2.2:  v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );

        return v;
    } // third(v)

    public Value fourth( final Value v ) {
        System.out.println( " 4.1.1:entered: v.i = " + v.i ); // 9
        System.out.println( " 4.1.2:v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );

        /**********************************
        // The final local v can't be assigned. It must be blank and not using a compound assignment.
        // meaning, you are not allowed to change its memory location,
        // but can alter its content, if permitted
        // v = new Value();
        //**********************************/

        v.i = 45;
        System.out.println( " 4.2.1:changed: v.i = " + v.i ); // 45
        System.out.println( " 4.2.2:v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );

        return v;
    } // fourth(v)

    public void first() {
        System.out.println( "1.1.1: entered: ..." );

        Value v = new Value();
        System.out.println( "1.2.1: created; v.i = " + v.i ); // 15
        v.i = 25;
        System.out.println( "1.2.2: changed: v.i = " + v.i ); // 25
        System.out.println();

        System.out.println( "1.3.1: before calling second(v) ..." );
        System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
        second( v );
        System.out.println( "1.3.2: returning from second(v) ..." );
        System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
        System.out.println();

        System.out.println( "1.4.1:  before calling third(v) ..." );
        System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
        v = third( v );
        System.out.println( "1.4.2:  returning from third(v) ..." );
        System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
        System.out.println();

        System.out.println( "1.5.1: before calling fourth(v) ..." );
        System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
        v = fourth( v );
        System.out.println( "1.5.2: returning from fourth(v) ..." );
        System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
    } // first()

    public static void main( String ... a ) {
        Test _this = new Test();
        _this.first();
    } // psvm(...)
} // class Test

When you run the above example, you may see an output as below:

1.1.1: entered: ...
1.2.1: created; v.i = 15
1.2.2: changed: v.i = 25

1.3.1: before calling second(v) ...
 v.i = 25, v.hashCode() = 1671711; v = Test$Value@19821f
 2.1.1: entered: v.i = 25
 2.1.2: v.hashCode() = 1671711; v = Test$Value@19821f
 2.2.1:   new V: v.i = 9
 2.2.2: v.hashCode() = 11394033; v = Test$Value@addbf1
1.3.2: returning from second(v) ...
 v.i = 25, v.hashCode() = 1671711; v = Test$Value@19821f

1.4.1:  before calling third(v) ...
 v.i = 25, v.hashCode() = 1671711; v = Test$Value@19821f
 3.1.1:  entered: v.i = 25
 3.1.2:  v.hashCode() = 1671711; v = Test$Value@19821f
 3.2.1:  created: v.i = 9
 3.2.2:  v.hashCode() = 4384790; v = Test$Value@42e816
1.4.2:  returning from third(v) ...
 v.i = 9, v.hashCode() = 4384790; v = Test$Value@42e816

1.5.1: before calling fourth(v) ...
 v.i = 9, v.hashCode() = 4384790; v = Test$Value@42e816
 4.1.1:entered: v.i = 9
 4.1.2:v.hashCode() = 4384790; v = Test$Value@42e816
 4.2.1:changed: v.i = 45
 4.2.2:v.hashCode() = 4384790; v = Test$Value@42e816
1.5.2: returning from fourth(v) ...
 v.i = 45, v.hashCode() = 4384790; v = Test$Value@42e816

If you really want to hold the changes made to an object instanceVariableV in a called method, say fifth(), the other possibility is to declare v as instance variable.

Following example will explain the differences.

public class Test {
    Value instanceVariableV = null; // v

    // rest of other variables and methods here
        // ...

    public void fifth() {
        System.out.println( " 5.1.1:entered: instanceVariableV = " + instanceVariableV ); // null
        // null, hence no hashCode(), and no toString() will work

        // let us create an instance of Value
        instanceVariableV = new Value();
        System.out.println( " 5.2.1:created: instanceVariableV = " + instanceVariableV ); // Test$Value@9304b1
        System.out.println( " 5.2.2: instanceVariableV.i = " + instanceVariableV.i ); // 15
        System.out.println( " 5.2.3: hashCode = " + instanceVariableV.hashCode() ); // 9634993

        instanceVariableV.i = 20;
        System.out.println( " 5.3.1:changed: instanceVariableV.i = " + instanceVariableV.i ); // 20
        System.out.println( " 5.3.2: hashCode = " + instanceVariableV.hashCode() ); // 9634993 // not changed 
    } // fifth()

    public void first() {
        // continuation of code

        System.out.println( "1.6.1: before calling fifth() ..." );
        System.out.println( " instanceVariableV = " + instanceVariableV  );
        fifth();
        System.out.println( "1.6.2: returning from fifth() ..." );
        System.out.println( " instanceVariableV = " + instanceVariableV  );
        if ( instanceVariableV != null ) {
            // must be different from the one when created new
            System.out.println( " .i = " + instanceVariableV.i );
            // this won't differ
            System.out.println( " .hashCode() = " + instanceVariableV.hashCode() );
        }
    } // first()

    public static void main( String ... a ) {
        // ...
        System.out.println( "\r\nmain(...): vInstanceVariable = " + _this.instanceVariableV );
        if ( _this.instanceVariableV != null ) {
            // must be different from the one when created new
            System.out.println( " .i = " + _this.instanceVariableV.i );
            // this won't differ
            System.out.println( " .hashCode() = " + _this.instanceVariableV.hashCode() );
        }
    } // psvm(...)

When you run with the above extended example, you may see an output as below:

1.6.1: before calling fifth() ...
 instanceVariableV = null
 5.1.1:entered: instanceVariableV = null
 5.2.1:created: instanceVariableV = Test$Value@9304b1
 5.2.2: instanceVariableV.i = 15
 5.2.3: hashCode = 9634993
 5.3.1:changed: instanceVariableV.i = 20
 5.3.2: hashCode = 9634993
1.6.2: returning from fifth() ...
 instanceVariableV = Test$Value@9304b1
 .i = 20, .hashCode() = 9634993

main(...): vInstanceVariable = Test$Value@9304b1
 .i = 20
 .hashCode() = 9634993

Hope this helps you.

Other references:

  1. Does Java pass by reference or pass by value?
  2. Is java pass by reference? (A posting on SO)
Community
  • 1
  • 1
Ravinder Reddy
  • 23,692
  • 6
  • 52
  • 82
2

When you pass v to second, what is passed by value is the reference that is stored in v. Recall that Java has only reference types, not object types like C++. Inside second, when you execute v.i = 20;, it changes the same object that is referenced by the local variable v in first. That change remains in place even when the parameter v is reassigned inside second.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • what cause me problem is I see in second v.i changed to 15 when i reassigned it.So how v.is 20 in the first method where v is the same for both method.I mean containing two different values – android May 25 '12 at 05:50
  • @android - Note first that you are assigning `v.i = 20` _before_ you assign a new value to `v` in `second`. The `v` in `second` is not the same variable as `v` in `first`. Inside `second`, `v` is initialized to the same value as `v` in `first` (a reference to an instance of `Value`) on entry because that was the argument to the call. However, assigning a new reference value inside `second` will not change the reference variable `v` in `first`. The fact that you gave them the same names does not make them the same (reference) variables. – Ted Hopp May 25 '12 at 06:04
  • second(Value v) this v's memory location is different from v in first? – android May 25 '12 at 06:11
  • @android - Yes. The value of `v` from `first` is copied onto the stack in order to create the parameter value passed into the call to `second`. That's why assigning a new value to `v` in `second` leaves `v` unchanged in `first`. However, the value that is copied is a _reference_ to an object, not the object itself. That's why `v.i = 20` in `second` changes the same object that is referenced by `v` in `first`. – Ted Hopp May 25 '12 at 14:22
0

Let me try and explain with an analogy

Imagine that your value object is a real object - a piece of paper with the number 15 written on it. You give that piece of paper to a friend named "First". First puts that piece of paper to one side and gets a new piece of paper, with 15 written on it, but crosses out the 15 and writes 25 on it.

He gives this second piece of paper to another friend named "Second". Second takes that piece of paper, crosses out the 25 that First wrote and writes 20 on it instead. He then picks up yet another piece of paper with the number "15" and shows that to you - you see the number 15. Then you ask First to show you the piece of paper that he gave to Second. You see that it says "20"

Steve Atkinson
  • 1,219
  • 2
  • 12
  • 30
  • 1
    Well.thanks for your nice explanation.He then picks up yet another piece of paper with the number "15" and shows that to you.He also replaced the previous paper with this one by v=val – android May 25 '12 at 06:52
0

All parameters in Java are value parameter. When you call method second: JVM will copy v object to v1, v1 has the same pointer to v. when you assign

1, When you set v.i = 20, the value of v and v1 is change to 20(because these object have the same pointer)

2, v = new Value();

that mean you assign v1 = new Value(); at this time, v1 and v have different pointer.

after you call method second, value of v is 20(step 1).

Sikorski
  • 2,653
  • 3
  • 25
  • 46
Nguyen
  • 1
  • 3