1

を使用して一意に生成されたIDによってクライアントを追跡するサーバーを作成しようとしていますHashMap<ClientID,Client>。私が管理者で、サーバーから誰かを起動したい場合は、適切なClientID(実際には単なる文字列です。唯一の違いはClientIDクラスが2つのクライアントがないことを確認する作業を行うことです)を検索するという考え方です。そのクライアントに同じIDを割り当てたことがあります)、「キック12」などのコマンドを入力します(キックしたい人のClientIDがたまたま12だった場合)。私はこれがうまくいくと思ったので、HashMapObjectから継承されたhashCode()メソッドの内部使用によってサポートされている可能性があり、それがtrueであると仮定して、必要なルックアップ操作をサポートするようにClientIDクラスを設計しました。しかし、明らかに、それは真実ではありません。同じハッシュコードを持つ2つのキーは、HashMap(またはHashSet)の同じキーとは見なされないようです。私がHashSetやりたいことを説明するために、を使用して簡単な例を作成しました。

importjava.lang。*;
java.io.*をインポートします。
importjava.util。*;

クラスClientID{
    プライベート文字列ID;

    public ClientID(String myId)
    {{
        id = myId;
    }

    public static ClientID generateNew(Set <ClientID> previous)
    {{
        ClientID res = new ClientID( "");
        ランダムrand=new Random();
        行う {
            int p = rand.nextInt(10);
            res.id + = p;
        } while(existing.contains(res));
        resを返します。
    }

    public int hashCode()
    {{
        return(id.hashCode());
    }

    public boolean equals(String otherID)
    {{
        return(id == otherID);
    }

    public boolean equals(ClientID other)
    {{
        return(id == other.id);
    }

    public String toString()
    {{
        IDを返します。
    }

    public static void main(String [] args)はIOException{をスローします
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        HashSet <ClientID> mySet = new HashSet <ClientID>();
        ClientID myId = ClientID.generateNew(mySet);
        mySet.add(myId);
        文字列入力;
        行う {
            System.out.println( "セット内のID/ハッシュコードのリスト:");
            for(ClientID x:mySet)
                System.out.println( "\ t" + x.toString()+ "\ t" + x.hashCode());
            System.out.print( "\ nセットに含まれているかどうかをテストするIDを入力してください:");
            input = in.readLine();
            if(input == null)
                壊す;
            else if(input.length()== 0)
                継続する;
            ClientID matchID = new ClientID(input);
            if(mySet.contains(matchID))
                System.out.println( "Success!SetにはすでにそのIDが含まれています:)");
            そうしないと {
                System.out.println("IDの追加"+ matchID.toString()+ "(hashcode" + matchID.hashCode()+ ")をセットに");
                mySet.add(matchID);
            }
            System.out.println( "\ n");
        } while(!input.toUpperCase()。equals( "QUIT"));
    }
}

このコードを使用すると、(私が知る限り)出力を生成することは不可能です

成功!セットにはすでにそのIDが含まれています:)

...代わりに、値が重複している場合でも(つまり、equalsメソッドと等しく、同じハッシュコードを持っている場合でも)、そのセットに値を追加し続けます。私がこれをうまく伝えていない場合は、自分でコードを実行すると、私が何を意味するのかすぐにわかると思います...これにより、ルックアップが不可能になります(また、Client.generateNewメソッドが意図したとおりに機能しないことも意味します)に); どうすればこれを回避できますか?

4

3 に答える 3

4

Javaでは、特定のクラスがハッシュのキーとして機能するためには、2つのメソッドを実装する必要があります。

public int hashCode();
public boolean equals(Object o);

これらのメソッドはコヒーレントに動作する必要があります。あるオブジェクトが別のオブジェクトと等しい場合、それらのオブジェクトは同じハッシュを生成する必要があります。

の署名に注意してくださいequals(Object o)。メソッドequalsオーバーロードしていますが、 オーバーライドequalsする必要があります。 equals(Object o)

他の人が指摘しているように、オーバーライドequalsされたメソッドも壊れてStringいます。これは、値ではなくIDを比較しているためです。を介して比較する代わりにstr1 == str2、を使用しますstr1.equals(str2)

コードに次の修正を加えると、正常に機能し始めるはずです。

public boolean equals(Object o){
    return o instanceof ClientID ? this.equals((ClientID) o);
}

public boolean equals(String otherID) {
    return id.equals(otherID);
}

public boolean equals(ClientID other) {
    return id.equals(other.id);
}
于 2012-06-22T04:27:01.430 に答える
3

HashSet(およびHashMap)このObject.hashCodeメソッドを使用して、オブジェクトが入るハッシュバケットを決定しますが、そのオブジェクトがそのバケット内の別のオブジェクトと等しいかどうかは判断しません。そのために、彼らはを使用しますObject.equals。あなたの場合、文字列IDの参照の同等性(「実際の」同等性ではなく、文字列の同等性)を使用してそのメソッドを実装しようとしました。equalsまた、をオーバーライドするのではなく、の新しいオーバーロードを作成しましたObject.equals

を使用して文字列を比較できない理由について、SOで多くの質問を検索できます==が、tl; drバージョンでは、オーバーライドする必要がありますboolean equals(Object)(同じ名前のオーバーロードされたメソッドではなく、そのメソッドは正確に-it )を取得Objectし、着信オブジェクトが、このClientIDの文字列ID equals(ont ==s)の文字列IDを持つClientIDであることを確認する必要があります。

于 2012-06-22T04:31:56.483 に答える
0

ところで、この投稿を読んでいるすべての人:

uouは、子タイプのハッシュコードが可変状態に依存する場合に備えて、ハッシュコードによって子を太らせるJavaコレクションにすべて注意する必要があります。例:

HashSet<HashSet<?>> or HashSet<AbstaractSet<?>> or HashMap varient:

HashSetは、hashCodeによってアイテムを取得しますが、アイテムタイプはHashSetであり、hashSet.hashCodeはアイテムの状態によって異なります。

その問題のコード:

HashSet<HashSet<String>> coll = new HashSet<HashSet<String>>();
HashSet<String> set1 = new HashSet<String>();
set1.add("1");
coll.add(set1);
print(set1.hashCode); //---> will output X
set1.add("2");
print(set1.hashCode); //---> will output Y
coll.remove(set1) // WILL FAIL TO REMOVE (SILENTLY)

終了コード

-理由は、HashSetのremoveメソッドがHashMapを使用し、hashCodeによってキーを識別するのに対し、AbstarctSetのhashCodeは動的であり、それ自体の可変プロパティに依存します。

それが役立つことを願っています

于 2015-02-28T21:51:12.173 に答える