ArrayListのcontains()メソッドはどのようにオブジェクトを評価しますか?


303

たとえば、1つのオブジェクトを作成してmyに追加するとしますArrayList。次に、まったく同じコンストラクター入力で別のオブジェクトを作成した場合、contains()メソッドは2つのオブジェクトを同じであると評価しますか?コンストラクターが入力に対して何もおかしくなく、両方のオブジェクトに格納されている変数が同一であると想定します。

ArrayList<Thing> basket = new ArrayList<Thing>();  
Thing thing = new Thing(100);  
basket.add(thing);  
Thing another = new Thing(100);  
basket.contains(another); // true or false?

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    equals (Thing x) {
        if (x.value == value) return true;
        return false;
    }
}

これclassは、contains()リターンを実装するためにどのように実装する必要がありtrueますか?

回答:


339

ArrayList implementsリストインターフェース。

あなたが見ればのJavadocListcontains方法あなたはそれが使用されていることがわかりますequals()2つのオブジェクトが同じかどうかを評価する方法を。


61
equals()をオーバーライドする場合に備えて、hashcode()メソッドもオーバーライドするようにしてください。そうしないと、コレクションを使用しているときに物事が期待どおりに動作しない可能性がありますか?
Mohd Farid、2010

34
これは正解ですが、Objectではなくを受け入れるようにequalsメソッドを変更する必要があることに注意してくださいThing。そうしないと、equalsメソッドは使用されません。:)
mdierker 2013

1
Eclipseの[ソース]メニューに[hashCode()と等しいを生成]があることがわかった。
Volodymyr Krupach

これは、タイトルの質問には答えますが、説明の質問には答えません。つまり、「まったく同じコンストラクター入力で別のオブジェクトを作成すると、contains()メソッドは2つのオブジェクトが同じであると評価しますか?」
robguinness 2017年

3
Collections最適化された方法で処理を実行しcontains()ます。つまり、最初hashCodeに2つのオブジェクトのsをチェックし、次にを呼び出しますequals()。場合hashCodesは(常に二つの異なるインスタンスの場合である異なるThing)、equals()メソッドが呼び出されません。経験則として、をオーバーライドするときは、オーバーライドすることもequals()忘れないでくださいhashCode()
Sevastyan Savanyuk

52

正しい実装は

public class Thing
{
    public int value;  

    public Thing (int x)
    {
        this.value = x;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean sameSame = false;

        if (object != null && object instanceof Thing)
        {
            sameSame = this.value == ((Thing) object).value;
        }

        return sameSame;
    }
}

1
ifステートメントは不要です。instanceof十分です
Paul

@Paulあなたが話している声明のどの部分ですか?
ChristopheCVB

4
object != nullための条件は、不要であるobject instanceof Thingオブジェクトのチェックはあまりにもヌルではないされています。
Alexander Farber

15

ArrayListは、クラス(あなたのケースのThingクラス)に実装されているequalsメソッドを使用して、equalsの比較を行います。


12

一般に、パフォーマンスを向上させるためだけでも、をオーバーライドするhashCode()たびにオーバーライドする必要がありますequals()HashCode()比較を行うときにオブジェクトがどの「バケット」にソートされるかを決定するため、equal()true と評価される2つのオブジェクトは同じを返す必要がありhashCode value()ます。のデフォルトの動作を思い出せませんhashCode()(0が返された場合、コードは機能しますが、アドレスが返された場合、コードは失敗します)。オーバーライドするのを忘れたためにコードが失敗したときのことを覚えていますhashCode()。:)


7

オブジェクトに対してequalsメソッドを使用します。したがって、Thingがequalsをオーバーライドして、オブジェクトに格納されている変数を比較に使用しない限り、contains()メソッドでtrueは返されません。


6
class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    equals (Thing x) {
        if (x.value == value) return true;
        return false;
    }
}

あなたは書く必要があります:

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    public boolean equals (Object o) {
    Thing x = (Thing) o;
        if (x.value == value) return true;
        return false;
    }
}

今では動作します;)


6
Thing x =(Thing)o;を実行しないでください。最初に他のオブジェクトがnullであるかどうかを確認せずに
steelshark 2013年

5

valueがプリミティブ型でない場合、次の実装は間違っていることに注意したいだけです。

public class Thing
{
    public Object value;  

    public Thing (Object x)
    {
        this.value = x;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean sameSame = false;

        if (object != null && object instanceof Thing)
        {
            sameSame = this.value == ((Thing) object).value;
        }

        return sameSame;
    }
}

その場合、私は以下を提案します:

public class Thing {
    public Object value;  

    public Thing (Object x) {
        value = x;
    }

    @Override
    public boolean equals(Object object) {

        if (object != null && object instanceof Thing) {
            Thing thing = (Thing) object;
            if (value == null) {
                return (thing.value == null);
            }
            else {
                return value.equals(thing.value);
            }
        }

        return false;
    }
}

重複を排除しながらこれを実装する方法?
Sujay

4

他のポスターは、contains()がどのように機能するかについての質問に対処しています。

あなたの質問の同様に重要な側面は、equals()を適切に実装する方法です。そして、これに対する答えは、この特定のクラスのオブジェクトの等価性を構成するものに本当に依存しています。あなたが提供した例では、x = 5の2つの異なるオブジェクトがある場合、それらは等しいですか?それは本当にあなたがやろうとしていることに依存します。

オブジェクトの等価性のみに関心がある場合、.equals()のデフォルトの実装(Objectによって提供されるもの)はIDのみを使用します(つまり、this == other)。それが必要な場合は、クラスにequals()を実装しないでください(Objectから継承させます)。あなたが書いたコードは、あなたがアイデンティティを求めているのであればある程度正しいですが、実際のクラスb / cには決して現れません。デフォルトのObject.equals()実装を使用するよりもメリットはありません。

このようなものを使い始めたばかりの場合は、Joshua BlochによるEffective Javaの本を強くお勧めします。これは素晴らしい読み物であり、この種のことをカバーしています(さらに、IDベースの比較以上のものを実行しようとしているときに、equals()を正しく実装する方法)


私の目的のために、等しい値のオブジェクトがArrayListにあるかどうかを確認しようとしました。それは一種のハックだと思います。本の推薦をありがとう
Mantas Vidutis 2010

3

JavaDocからのショートカット:

boolean contains(Object o)

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.