0

次のような状況があります。キーを文字列として持つJavaのHashMapがあります。次に、ある段階で、実行時に、そのマップからデータを取得するために、これらのキーに等しい文字列を作成します。文字列は、「for」ループ内で次のように作成されます。

 String keyToRetrive = "lights[" + Integer.toString(i) + "]" + ".Intensity";

奇妙なことは、マップを反復してその文字列に等しいキーを見つけると、一致が見つかった場合でも検索がステップオーバーすることです。したがって、この検索ループでは:

  while (iter.hasNext()) {
        Map.Entry entry = (Map.Entry) iter.next();
        if (name == entry.getKey()) {  ///name- "lights[0].Intesity"
            uniformOut = (ICleanable) entry.getValue();
            break;
        }
    }

「lights[0].Intesity」という名前のキーは、マップに含まれている場合でもtrueを返すことはありません.どのように解決したか.比較された両方の文字列値にhashCode()を使用しました.したがって、このバージョンは機能します:

 while (iter.hasNext()) {
        Map.Entry entry = (Map.Entry) iter.next();
        if (name.hashCode() == entry.getKey().hashCode()) {
            uniformOut = (ICleanable) entry.getValue();
            break;
        }
    }

更新: 「==」がうまく機能せず、「equals()」を使用する必要があるという事実を指摘された後、質問を絞り込みたいと思います:連結ブロック?つまり、比較するキー文字列を単純な単一の文字列として定義すると、次のようになります。

 String foo="foo";

このような文字列は、「==」を使用して HashMap キーと比較されます。

私は専門の Java プログラマーではないので、なぜこのように動作するのか誰か説明できますか?

4

3 に答える 3

8

==演算子を使用して文字列を比較しています。equals()代わりに使用してください:

name.equals(entry.getKey())

これは Java でよくある落とし穴です。「Java で文字列を比較するにはどうすればよいですか?」を参照してください。Equals/equalsと== 演算子の違いは? .


toString()ところで(あなたの問題とは無関係)、明示的に呼び出す必要のない文字列を連結するときは、次のようになります。

"lights[" + Integer.toString(i) + "]" + ".Intensity"

次のように置き換えることができます:

"lights[" + i + "]" + ".Intensity"

iだけでなく、あらゆるタイプで機能しますint

于 2012-06-26T06:37:53.503 に答える
5

を使用してオブジェクトを比較すると==「参照の等価性」比較が実行されます。つまり、2 つの参照がメモリ内の同じStringオブジェクトを指しているかどうかをチェックしていることになります。C に精通している場合は、次のようになります。

char* a = some_string();
char* b = some_other_string();
if (a == b) { ... }

一方、 を使用してオブジェクトを比較する.equals()場合は、「構造的同等性」比較を実行していることになります。つまり、2 つのオブジェクトに同等のデータが含まれているかどうかを確認していることになります。繰り返しますが、これの C 版は次のようになります。

char* a = some_string();
char* b = some_other_string();
if (strcmp(a, b) == 0) { ... }

ここで、本当にやりたくないことは、2 つのオブジェクトのハッシュ コードを比較することです。なぜだめですか?同じハッシュ コードを持つ 2 つのオブジェクトが必ずしも等しいとは限らないためです。そうかもしれませんが、正しく信頼することはできません。


更新:==文字列リテラルで機能する理由についても尋ねました。その答えは、Java コンパイラが定数文字列をヒープに割り当てないためです。代わりに、それらが使用されるクラスの定数プールに格納されます。したがって、次のように書くと:

String foo1 = "foo";
String foo2 = "foo";

次に、コンパイラは、両方の参照がクラスの定数プール内の同じ場所を指すようにします。ただし、次のように記述した場合:

String foobar1 = "foobar";
String foobar2 = "foo" + bar();
String bar() { return "bar"; }

foobar2コンパイラは、が と論理的に同等であることを判断できるほど賢くありませんfoobar1。ただし、2 つの変数がコンパイル時の定数であることがわかっている場合でも、単純なままにして を使用する必要があります.equals()

于 2012-06-26T06:57:11.360 に答える
0

ただし、他の人はあなたのコードが機能しない理由を述べています:

1) HashMap を使用している場合は、エントリのインターレーターではなく、map.get(key) を使用して値を取得する必要があります。それがハッシュマップの要点です。

2) ジェネリックを使用し、明示的にキャストすることはできるだけ避けてください。

于 2012-06-26T07:11:41.330 に答える