6

この質問をするのは初心者のように感じますが、以下の Set をメソッドに渡して新しい HashSet を指すと、それでも EmptySet として表示されるのはなぜですか? ローカル変数がスタックに割り当てられているためで、メソッドを終了すると新しい変数が吹き飛ばされますか? どうすれば同等の機能を達成できますか?

import java.util.HashSet;
import java.util.Set;

public class TestMethods {

    public static void main(final String[] args) {

        final Set<Integer> foo = java.util.Collections.emptySet();
        test(foo);

    }

    public static void test(Set<Integer> mySet) {

        mySet = new HashSet<Integer>();

    }

}
4

6 に答える 6

8

Java は値によって参照を渡します。参照mySetの単なるコピーと考えてfooください。ではvoid test(Set<Integer> mySet)mySet変数はその関数内の単なるローカル変数であるため、別の値に設定しても呼び出し元には影響しませんmain

mySetfooただし、変数と同じ Set を参照 (または必要に応じて「ポイント」)しmainます。

メインの参照を変更する場合は、次のようにします。

foo = test(); //foo can't be final now though
 public static Set<Integer>  test() {
   return new HashSet<Integer>();
}
于 2010-07-20T01:31:56.583 に答える
8

...ローカル変数がスタックに割り当てられているためで、メソッドを終了すると新しいものが吹き飛ばされますか?

いいえ。これは、Java の引数受け渡しセマンティクスによるものです。

Java 引数は「値渡し」で渡されますが、オブジェクトまたは配列型の場合、渡す値はオブジェクト/配列参照です。新しいセット オブジェクトを作成して に割り当てるときはmySet、ローカル変数/パラメータを設定するだけです。Java は値渡しを使用するため、これはメソッド内のfoo変数には影響しません。main

メソッドに入ると、メソッドで作成されたインスタンスtestへの参照の 2 つのコピーがあります。1つと1つ。次に、コードは の参照を新しく作成された への参照に置き換えますが、この新しい参照は呼び出し元に返されません。(コードを変更して、たとえばメソッドの結果として返すこともできます。ただし、これは明示的に行う必要があります。)HashSetmainfoomySetmySetHashSettest

OK - ただし、メソッド呼び出し内で追加またはその他の操作を行う場合、その割り当ては保持されます。何故ですか?

これは、fooまたはの参照を使用してインスタンス メソッドを呼び出すと、参照が参照mySetするオブジェクト ( HashSet) でそのメソッドが実行されるためです。2 つの参照が同じオブジェクトを指していると仮定すると、「割り当ては保持されます」。より正確には、同じオブジェクトへの他の参照に対する操作を介して、オブジェクトへの 1 つの参照に対する操作の影響を観察できます。

Java メソッド呼び出しは、オブジェクト自体ではなく、オブジェクトへの参照をコピーすることを覚えておいてください。

ところで、 によって返されるセットに要素を追加することはできませんCollections.emptySet()。そのセット オブジェクトは不変です。(たとえば)addそれを呼び出すと、例外がスローされます。

于 2010-07-20T01:32:34.773 に答える
1

'foo'は、test()呼び出しに入る空のセットを参照しましたが、テスト呼び出しはそのオブジェクトを変更しなかったため、そこから戻ったときはまだ空のセットです。

test()メソッド内では、「mySet」は単なるローカル参照であり、エントリ時に元のセット(foo)を参照します。その参照に新しいハッシュセットを割り当てると、元のセットへの参照が失われます。 。ただし、Javaはtest()に元のセットへの参照の複製を与えただけなので、これらの効果はすべてtest()メソッドに対して完全にローカルです。

これで、test()内で、元のオブジェクトへの参照があるため、そのオブジェクトを変更できます。たとえば、そのセットに要素を追加できます。ただし、呼び出し元の関数で参照を変更することはできません。変更できるのは、参照するものだけです。したがって、あるコレクションを別のコレクションに置き換えることはできません。そもそもHashSetが必要な場合は、main()でHashSetを新しくする必要があります。

于 2010-07-20T01:44:54.803 に答える
0
import java.util.HashSet;
import java.util.Set;

public class TestMethods {

    public static void main(final String[] args) {

        final Set<Integer> foo = java.util.Collections.emptySet();
        test(foo);

    }

    public static void test(Set<Integer> mySet) {
        // here mySet points to the same object as foo in main
        mySet = new HashSet<Integer>();
        // mySet now points to a new object created by your HashSet constructor call,
        // any subsequent operations on mySet are no longer associated with foo, because
        // they are no longer referencing the same object
    }
}

どうすれば同等の機能を実現できますか?

この質問を理解できるかどうかわかりませんが、返品をお探しですか?

    public static Set<Integer> test(Set<Integer> mySet) {
        for(Integer i : mySet){
            // do something??
        }
        mySet = new HashSet<Integer>();
        return mySet;
    }

ここで、テストが返すものにfooを割り当てると、「同等の機能」が得られますか?

于 2010-07-20T01:44:42.563 に答える
0

あなたはこの本を読むべきです:

「Java SCJP 認定のプログラマー向けガイド: 総合入門書 (第 3 版)」

于 2010-10-27T18:45:35.230 に答える
0

質問を理解しているかどうかわかりません。このメソッドでは、新しいセットをインスタンス化し、それをローカル変数 testに割り当てています。その後、で戻ったときと同じセットを参照しなくなります。mySetmySetfooMain

メソッドから戻ると、 foo は引き続きオリジナルemptySet()を参照HashSetし、メソッドで作成されたものはガベージ コレクションの対象としてマークされます。

于 2010-07-20T01:35:58.300 に答える