0

次のプログラム出力

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

どちらの場合も15ではない理由。値のオブジェクトが渡された後、2番目のメソッドでオブジェクト参照が変更されます。2番目のメソッドは15である必要があり、1番目のメソッドのように見えます。

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);
    }
}
4

4 に答える 4

2

に渡す場合、値によって渡されるのは、に格納されてvいる参照です。Javaには参照型のみがあり、C++のようなオブジェクト型はないことを思い出してください。内部では、を実行すると、のローカル変数によって参照されるのと同じオブジェクトが変更されます。この変更は、パラメータが内で再割り当てされた場合でもそのまま残ります。secondvsecondv.i = 20;vfirstvsecond

于 2012-05-25T05:45:35.863 に答える
1

Javaメソッドの実装は、正確ではありませんが。 call by[reference to, in case of objects,]valuecall by reference

オブジェクトを渡すということValue vは、インラインのメソッドスコープ変数がメソッドで作成されvたオブジェクトを参照していることを意味します。つまり、によって参照される同じオブジェクトへの変更は、呼び出し側にも反映されます。ただし、メソッドでは、メソッドスコープ変数を指す新しいオブジェクトを作成しています。この新しいオブジェクトのメモリ位置は、渡されたメソッドパラメータの位置と同じではありません。違いを特定するには、参照変数を使用して作成されたオブジェクトを確認します。 vfirst()vsecondValuevhashCode

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

これがお役に立てば幸いです。

その他の参考資料:

  1. Javaは参照渡しですか、それとも値渡しですか?
  2. Javaは参照渡しですか?(SOへの投稿)
于 2012-05-25T09:19:56.317 に答える
0

アナロジーで説明してみましょう

値オブジェクトが実際のオブジェクトであると想像してください。15という数字が書かれた一枚の紙です。あなたはその一枚の紙を「ファースト」という名前の友人に渡します。まず、その紙を片面に置き、15が書かれた新しい紙を手に入れますが、15を消して、25を書きます。

彼はこの2枚目の紙を「Second」という名前の別の友人に渡します。セカンドはその一枚の紙を取り、ファーストが書いた25を消し、代わりに20を書きます。次に、彼は番号「15」のさらに別の紙を手に取り、それをあなたに示します-あなたは番号15を見るでしょう。それからあなたはファーストに彼がセカンドに与えた一枚の紙を見せるように頼みます。「20」と表示されているのがわかります

于 2012-05-25T06:43:27.297 に答える
0

Javaのすべてのパラメーターは値パラメーターです。メソッドを呼び出すと、 secondJVMはvオブジェクトをv1にコピーします。v1は、への同じポインタを持ちますv。割り当てるとき

1、を設定すると、とv.i = 20の値が20に変更されます(これらのオブジェクトは同じポインタを持っているため)vv1

2 、v = new Value();

つまりv1 = new Value(); 、この時点で割り当てると、v1とvのポインターが異なります。

メソッドを呼び出した後second、vの値は20になります(ステップ1)。

于 2013-07-10T03:28:24.263 に答える