web-dev-qa-db-ja.com

HashSetに重複したエントリが含まれています

HashSetは、equalsメソッドで値が同じであると言った場合にのみ、値1を格納します。私もそう思っていました。

しかし、equalsメソッドがtrueを返し、セットのサイズがまだ大きくなるHashSetに要素を追加していますか?ごめんなさい、混乱しています。私が間違っているいくつかのヒントはニースでしょう。

Element t1 = new Element(false, false, false, false);
Element t2 = new Element(true, true, true, true);
Element t3 = new Element(false, false, false, false);

if (t1.equals(t3))
    System.out.println("they're equal");

Set<Element> set = new HashSet<>();

set.add(t1);
set.add(t2);
set.add(t3);

System.out.println("set size: " + set.size());

したがって、この例では、コンソール出力は次のようになります。

彼らは等しい
セットサイズ:3

それは私には意味がありません。サイズは2にする必要がありますか?

14
tObi

問題は、ElementクラスがequalsおよびhashCodeメソッドをオーバーライドしていないか、これらの実装が壊れていることです。

から Object#equals メソッドjavadoc:

Equalsメソッドは、null以外のオブジェクト参照に同値関係を実装します。

  • これは再帰的です。null以外の参照値xの場合、x.equals(x)はtrueを返します。
  • これは対称です。null以外の参照値xおよびyについて、y.equals(x)がtrueを返す場合にのみ、x.equals(y)はtrueを返す必要があります。
  • これは推移的です。null以外の参照値x、y、zについて、x.equals(y)がtrueを返し、y.equals(z)がtrueを返す場合、x.equals(z)はtrueを返します。これは一貫しています。null以外の参照値xおよびyの場合、オブジェクトの等値比較で使用される情報が変更されていなければ、-x.equals(y)を複数回呼び出すと、常にtrueまたは一貫してfalseが返されます。
  • Null以外の参照値xの場合、x.equals(null)はfalseを返す必要があります。

から Object#hashCode メソッドjavadoc:

HashCodeの一般的な規約は次のとおりです。

  • Javaアプリケーションの実行中に同じオブジェクトで複数回呼び出される場合は常に、オブジェクトの等値比較で使用される情報が変更されない限り、hashCodeメソッドは常に同じ整数を返す必要があります。この整数は、アプリケーションのある実行から同じアプリケーションの別の実行まで一貫性を保つ必要はありません。
  • Equals(Object)メソッドに従って2つのオブジェクトが等しい場合、2つのオブジェクトのそれぞれでhashCodeメソッドを呼び出すと、同じ整数の結果が生成される必要があります。
  • Equals(Java.lang.Object)メソッドに従って2つのオブジェクトが等しくない場合、2つのオブジェクトのそれぞれでhashCodeメソッドを呼び出すと、異なる整数の結果が生成される必要はありません。ただし、プログラマは、異なるオブジェクトに対して異なる整数の結果を生成すると、ハッシュテーブルのパフォーマンスが向上する可能性があることに注意する必要があります。

これらのメソッドの実装がこれらのルールを満たしていることを確認し、SetHashSetによってサポートされている)が期待どおりに機能するようにします。

20
Luiggi Mendoza

オブジェクトにはさまざまなハッシュがあるため、HashSetはさまざまな「バケット」に「プット」します。

4

独自のモデルクラスがある場合は、以下の例のように機能するいくつかの基本的な関数を変更する必要があります。

実行コード:

HashSet<MyModel> models = new HashSet<MyModel>();

for (int i = 1; i < 5; i++)
    models.add(new MyModel(i + "", "Name :" + i + ""));

for (int i = 3; i < 5; i++)
    models.add(new MyModel(i + "", "Name :" + i + ""));

for (Object object : models)
    System.out.println(object);

モデルクラス:

/**
 * Created by Arun
 */
public static class MyModel {

    private String id = "";
    private String name = "";

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

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return getId();
    }

    @Override
    public boolean equals(Object obj) {
        return !super.equals(obj);
    }

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

}

お役に立てれば。

3
Arun

はい[〜#〜] final [〜#〜]でないクラスのオブジェクトで実装できます。

HashSetオブジェクトを追加する前に、2つのメソッドhashCode()およびequals()をチェックします。最初に、メソッドhashCode()をチェックします。ハッシュコードがsameである場合は、Setのオブジェクトのいずれかを使用し、次に、そのオブジェクトのequalsメソッドをチェックします。両方のオブジェクトの参照、つまりthis.obj1==objを比較します。これらが同じ参照である場合はtrueを返し、値が重複していることを意味します。 HashCodeとequalsメソッドをオーバーライドすることで、重複する最終でないオブジェクトを追加できます。 HashCode()では、同じパラメーターの場合に同じハッシュコードを返すことができます。

例を参照してください:

public class Product {
int i;
Product(int a)
{
    this.i=a;
}
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + i;
    return result;
}
@Override
public boolean equals(Object obj) {
    /*if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Product other = (Product) obj;
    if (i != other.i)
        return false;
    return true;*/
    return true;
}
}
`

`
import Java.util.HashSet;
import Java.util.Set;
public class Main {
public static void main(String[] args) {
    Product p1=new Product(1);
    Product p2=new Product(1);
    Product p3=new Product(1);
    Set s=new HashSet();
    s.add(p1);
    s.add(p2);
    s.add(p3);
    System.out.println(s.size());
}
}

出力は1になります。

PS:これらのメソッドをオーバーライドしない場合、デフォルトの動作を使用するため、出力は3になります。

1
Shailesh Modi