こんにちは。ハンドルネーム「Javaを復習する初心者」です。このサイトはプログラミング言語Javaの復習・学習をするブログです。プログラムの開発・実行はEclipseで行ってます。
スポンサーリンク
お知らせ
  • 参考文献のページ作りました。
  • Amazon.co.jpアソシエイトに参加していますが、参考文献の紹介はもしもアフィリエイトに統一しました。
  • 2016年10月9日からは投稿ペースを落とします。週1回くらいにする予定です。
スポンサーリンク

Setのcontainsメソッド

こんにちは。「Javaを復習する初心者」です。今回はSetインターフェースの実装のひとつであるHashSetでcontains()メソッドを使いました。結論から書くと、自前クラスを格納する場合、hashCode()メソッド、equals()メソッドをオーバーライドする必要があります。

冒頭で結論を書いてしまいましたが、以下、実験的な内容を記載します。

Setインターフェースを実装するクラスはいくつかあるのですが、そのうちのHashSet<E>という定義のクラスを使いました。このEはジェネリックスまたは総称型と呼ばれるものです。実際に使うときには具体的にクラス名を記述します。HashSet<E>はクラスEの集合を扱うことができます。

HashSet<E>クラスのインスタンスを格納し、そのインスタンスに要素を追加していきます。ある要素を含むかどうかを調べるためには、contains()メソッドを使います。

String型とInteger型

格納するクラスとして、最初は、String型とInteger型で試してみました。

以下にフローを書きます。

    1. Set<String>型変数を宣言し、HashSetのインスタンスを格納する。
    2. “test1″を追加する。
    3. “test2″を追加する。
    4. 以下を出力する
      “test2を含むか。” + [containsメソッドの結果]

    5. 以下を出力する
      “test3を含むか。” + [containsメソッドの結果]
    1. Set<Integer>型変数を宣言し、HashSetのインスタンスを格納する。
    2. 1を追加する。
    3. 2を追加する。
    4. 以下を出力する
      “2を含むか。” + [containsメソッドの結果]

    5. 以下を出力する
      “3を含むか。” + [containsメソッドの結果]

以下はソースと実行結果です。

package collectionsFrameworkTest;

import java.util.HashSet;
import java.util.Set;

public class HelloHashSetStringInteger {

    public static void main(String[] args) {

        Set<String> stringSet = new HashSet<>();

        stringSet.add("test1");
        stringSet.add("test2");

        System.out.println("test2を含むか。" + stringSet.contains("test2"));
        System.out.println("test3を含むか。" + stringSet.contains("test3"));

        Set<Integer> integerSet = new HashSet<>();

        integerSet.add(1);
        integerSet.add(2);

        System.out.println("2を含むか。" + integerSet.contains(2));
        System.out.println("3を含むか。" + integerSet.contains(3));

    }

}
test2を含むか。true
test3を含むか。false
2を含むか。true
3を含むか。false

contains()メソッドは引数で指定されたインスタンスがHashSetに含まれているかをtrue/falseで返却してくれます。上記は2回、HashSetのインスタンスを生成していますが、それぞれジェネリックスにString型とInteger型をしていしています。contains()メソッドで要素が含まれるかどうかがtrue/falseで返却されているのが分かります。

自前のクラスを指定

では、自前のクラスをジェネリックスに指定した場合、contains()メソッドは期待度通りの値を返却してくれるでしょうか。以下はフィールド2つを持つ、クラスです。フィールドに値を設定するコンストラクタのみ定義しています。

package collectionsFrameworkTest;

public class HelloHashSetStudent1 {

    public String id;
    public String name;

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

}

以下はソースと実行結果です。上記クラスをHashSetのジェネリックスに指定していますが、contains()メソッドが期待した結果を返却しません。

package collectionsFrameworkTest;

import java.util.HashSet;
import java.util.Set;

public class HelloHashSetClass1 {

    public static void main(String[] args) {

        Set<HelloHashSetStudent1> studentSet = new HashSet<>();

        studentSet.add(new HelloHashSetStudent1("1", "name1"));
        studentSet.add(new HelloHashSetStudent1("2", "name2"));

        System.out.println("2, name2を含むか。" + studentSet.contains(new HelloHashSetStudent1("2", "name2")));
        System.out.println("3, name3を含むか。" + studentSet.contains(new HelloHashSetStudent1("3", "name3")));


    }

}
2, name2を含むか。false
3, name3を含むか。false

なぜこのようなことになるかというと、HelloHashSetStudent1クラスがhashCode()メソッドとequals()を正しくオーバーライドしていないからです。

オーバーライドが必要

ではどのように実装すればよいのかということになりますが、Eclipseでは右クリックのメニューからこの2つのメソッドを自動生成することができます。以下は自動生成した結果です。

package collectionsFrameworkTest;

public class HelloHashSetStudent2 {

    public String id;
    public String name;

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

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        HelloHashSetStudent2 other = (HelloHashSetStudent2) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}

以下は上記クラスを使ったソースと実行結果です。

package collectionsFrameworkTest;

import java.util.HashSet;
import java.util.Set;

public class HelloHashSetClass2 {

    public static void main(String[] args) {

        Set<HelloHashSetStudent2> studentSet = new HashSet<>();

        studentSet.add(new HelloHashSetStudent2("1", "name1"));
        studentSet.add(new HelloHashSetStudent2("2", "name2"));

        System.out.println("2, name2を含むか。" + studentSet.contains(new HelloHashSetStudent2("2", "name2")));
        System.out.println("3, name3を含むか。" + studentSet.contains(new HelloHashSetStudent2("3", "name3")));


    }

}
2, name2を含むか。true
3, name3を含むか。false

今度はcontains()メソッドが期待通りの結果を返却してくれました。