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 a
fourth` 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:
- Does Java pass by reference or pass by value?
- Is java pass by reference? (A posting on SO)