5

SCJP (または現在の OCPJP) 試験の準備として、(参照) 値による受け渡しと不変性に関するいくつかの模擬問題に悩まされています。

私の理解では、変数をメソッドに渡すときは、実際のオブジェクト自体ではなく、その変数に到達する方法を表すビットのコピーを渡します。

送信するコピーは同じオブジェクトを指しているため、StringBuilder に追加するなど、そのオブジェクトが変更可能な場合は変更できます。ただし、Integer をインクリメントするなど、不変オブジェクトに対して何かを行うと、ローカル参照変数は新しいオブジェクトを指すようになり、元の参照変数はこれに気付かないままになります。

ここで私の例を考えてみましょう:

public class PassByValueExperiment
{

    public static void main(String[] args)
    {
        StringBuilder sb = new StringBuilder();
        sb.append("hello");
        doSomething(sb);
        System.out.println(sb);


        Integer i = 0;
        System.out.println("i before method call : " + i);
        doSomethingAgain(i);
        System.out.println("i after method call: " + i);
    }

    private static void doSomethingAgain(Integer localI)
    {
        // Integer is immutable, so by incrementing it, localI refers to newly created object, not the existing one
        localI++;
    }

    private static void doSomething(StringBuilder localSb)
    {
        // localSb is a different reference variable, but points to the same object on heap
        localSb.append(" world");
    }
}

質問: このように動作するのは不変オブジェクトだけで、可変オブジェクトは値渡し参照によって変更できますか? 私の理解は正しいですか、それともこの行動には他の特典がありますか?

4

2 に答える 2

6

言語レベルでは、可変オブジェクトと不変オブジェクトに違いはありません。不変性は、純粋にクラスの API のプロパティです。

この事実は、ラッパー型で使用できるようにするオートボクシングによってのみ混乱++し、オブジェクトに対する操作のように見えますが、実際にはそうではありません。代わりに、値をプリミティブに変換し、それをインクリメントし、結果をラッパー型に戻し、それへの参照を変数に割り当てるための構文糖衣です。

したがって、違いは++、パラメーターの受け渡しとは何の関係もない、プリミティブとラッパーで使用されたときにオペレーターが行うことです。

于 2011-12-02T13:17:21.987 に答える
5

Java 自体は、オブジェクトが不変であるかどうかを認識していません。いずれの場合も、参照またはプリミティブ値のいずれかである引数のを渡します。パラメータの値を変更しても、何の効果もありません。

明確にするために、このコードはパラメーターの値を変更しません。

localSb.append(" world");

これにより、パラメーターの値が参照するオブジェクト内のデータが変更されますが、これは非常に異なります。に新しい値を割り当てていないことに注意してくださいlocalSb

基本的に、次のことを理解する必要があります。

  • 式 (変数、引数、パラメーターなど) の値は、常に参照またはプリミティブ値のいずれかです。決して物ではありません。
  • Javaは常に値渡しセマンティクスを使用します。引数の値がパラメータの初期値になります。

それらをよく考えて、頭の中で「変数」「値」「対象」の概念を分けて考えると、物事はより明確になるはずです。

于 2011-12-02T13:11:01.827 に答える