4

私は当初、ここで質問したいと考えていた理論に基づくベスト プラクティスの質問のテストとしてこれを開始しましたが、その過程で、java.Set クラスでいくつかの興味深い動作を見つけました。最初は、このアプローチの潜在的な落とし穴を知りたかったのですが、まったく機能しないことがわかったので、その理由を知りたいと思います。

アプリのデータベース オブジェクトのコンテナーであるオブジェクトがいくつかあります。オブジェクトはすべて一意integer idの を持ち、hashCode()equals()は整数 ID によって定義されます (ハッシュセットに格納するため)。

ええと、ハッシュセットに ID のみが指定されたオブジェクトが含まれているかどうかを確認する機能が必要でした。確かに、オブジェクトの新しいインスタンスを作成して、その方法を確認できました。でも、念のために、それを達成できるかどうかを確認したかったのです。もちろん、これはハッシュマップでも些細なことなので、これは重要な質問ではありません。楽しみと知識のためだけです。

そこで、クラスを作成し、オブジェクトのインスタンスではなく ,を呼び出そうとしcontains()ました。integerもちろん、Netbeans はこれについて楽しい警告を出します

Suspicious call to java.util.Collection.contains:
Given object cannot contain instances of int (expected Person)

エラーを無視してコードを実行したところ、Java が equals メソッドを呼び出していないことにショックを受けました。System.out.println()検証のために equals メソッドに debugを配置しましたが、そうです、それは呼び出されていません。

以下に投稿されたコードでは、予想される出力は次のようになります (私の理論が正しかった場合):

Here
Yes
Here
Yes

または(私の理論が間違っていた場合):

Here
Yes
Here
No

ただし、出力は次のとおりです。

Here
Yes
No

equals メソッドが呼び出されていないことを証明する "No" の前に "Here" がないことに注意してください。

誰でも光を当てることができますか?equals()効率のためにこれを追加するように常に言われました:

if (!(obj instanceof Person))
    return false;

しかし、equals()そのような状況で呼び出されなければ意味がありません。

SSCCE は次のとおりです。

御時間ありがとうございます。

    import java.util.LinkedHashSet;
    import java.util.Set;

    /**
     *
     * @author Ryan
     */
    public class Test7 {
        public static void main(String[] args) {
            class Person {
                public final int id;
                public final String name;

                public Person(int id, String name) {
                    this.id = id;
                    this.name = name;
                }

                @Override
                public boolean equals(Object obj) {
                    System.out.println("Here");
                    if (this == obj)
                        return true;
                    if (obj instanceof Person)
                        return id  == ((Person)obj).id;
                    else if(obj instanceof Integer)
                        return id == (Integer)obj;
                    else {
                        System.out.println("Returning False");
                        return false;
                    }
                }

                @Override
                public int hashCode() {
                    return id;
                }
            }

            Set<Person> set = new LinkedHashSet<Person>();
            set.add(new Person(1, "Bob"));
            set.add(new Person(2, "George"));
            set.add(new Person(3, "Sam"));


            if(set.contains(new Person(1, "Bob")))
                System.out.println("Yes");
            else
                System.out.println("No");

            if(set.contains(1))
                System.out.println("Yes");
            else
                System.out.println("No");
        }
    }
4

1 に答える 1

5

これは、セット内の要素ではなく、提供されたオブジェクトに対して比較が行われるためです。HashSet#contains(Object)から:

このセットに指定された要素が含まれている場合は true を返します。より正式には、このセットに(o==null ? e==null : o.equals(e))のような要素 e が含まれている場合にのみ true を返します。

したがって、あなたの例では、のような integer.equals(person)比較を行うことになります。したがって、セットにPersonオブジェクトが含まれている場合、if(obj instanceof Integer)条件はチェックされませんが、セットに Integerオブジェクトが含まれている場合、その条件は満たされ、チェックされます。

于 2013-06-03T01:16:03.400 に答える