Javaメソッドの実装は、正確ではありませんが。 call by
[reference to, in case of objects,]
value
call by reference
オブジェクトを渡すということValue v
は、インラインのメソッドスコープ変数がメソッドで作成されv
たオブジェクトを参照していることを意味します。つまり、によって参照される同じオブジェクトへの変更は、呼び出し側にも反映されます。ただし、メソッドでは、メソッドスコープ変数を指す新しいオブジェクトを作成しています。この新しいオブジェクトのメモリ位置は、渡されたメソッドパラメータの位置と同じではありません。違いを特定するには、参照変数を使用して作成されたオブジェクトを確認します。 v
first()
v
second
Value
v
hashCode
v
したがって、 inメソッドのインスタンス変数を変更してもsecond
、メソッドが変更されたオブジェクトを返さない限り、メソッドの呼び出し元には返されません。メソッドはここを返しvoid
ます。
プログラマーは、ほとんどの場合、呼び出し元と呼び出されたメソッドで使用されているのと同じ参照名と混同されます。
違いを理解するには、次の例を見てください。third' and a
さらに説明するために、4番目の`メソッド を含めました。
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
上記の例を実行すると、次のような出力が表示される場合があります。
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
instanceVariableV
呼び出されたメソッドでオブジェクトに加えられた変更を本当に保持したい場合、たとえば、他の可能性はインスタンス変数としてfifth()
宣言することです。 v
次の例で違いを説明します。
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(...)
上記の拡張例を使用して実行すると、次のような出力が表示される場合があります。
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
これがお役に立てば幸いです。
その他の参考資料:
- Javaは参照渡しですか、それとも値渡しですか?
- Javaは参照渡しですか?(SOへの投稿)