正しくJavaで木のためのequals()を、hashCode()メソッドを実装するには?

FreeOnGoo:

私は、ツリー構造を持っていると私は等しいメソッドをオーバーライドする必要がある/ハッシュコードを、私はユニットテストに期待される結果のチェックを使用しているため。

ツリー型構造の問題点は、再帰的に相互に参照していることです。特に、子供やその逆のための両親。

そして、すべてのフィールドは、メソッドで使用されている場合は、等しい/のhashCode、その後、ループが存在します。質問が正しく契約に違反しないようにするために、次にオーバーライドする方法です。

私はそれを実装する方法の例を与えます。

public class App {
    public static void main(String[] args) {
        Book book1 = new Book(1L, "The catcher in the rye");
        Book book2 = new Book(2L, "Rich Dad Poor Dad");

        BookTree bookTree1 = new BookTree(book1);
        BookTree bookTreeChild1 = new BookTree(book2);
        bookTree1.addChild(bookTreeChild1);

        BookTree bookTree2 = new BookTree(book1);
        BookTree bookTreeChild2 = new BookTree(book2);
        bookTree2.addChild(bookTreeChild2);

        if (!bookTree1.equals(bookTree2)) {
            throw new RuntimeException("Invalid override equals");
        }
    }
}

class Book {
    private Long id;
    private String name;

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

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public boolean equals(Object object) {
        if (this == object) return true;
        if (object == null || getClass() != object.getClass()) return false;
        Book book = (Book) object;
        return Objects.equals(id, book.id) &&
                Objects.equals(name, book.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}

class Tree<T> {
    private List<Tree<T>> children = new ArrayList<>();
    private Tree<T> parent = null;
    private T data;

    public Tree(T data) {
        this.data = data;
    }

    public Tree(T data, Tree<T> parent) {
        this.data = data;
        parent.addChild(this);
    }

    public List<Tree<T>> getChildren() {
        return children;
    }

    public void addChild(Tree<T> child) {
        child.setParent(this);
        this.children.add(child);
    }

    public void addChild(T data) {
        Tree<T> newChild = new Tree<>(data);
        this.addChild(newChild);
    }

    public void removeChildren() {
        this.children = new ArrayList<>();
    }

    public void addChildren(List<Tree<T>> children) {
        for(Tree<T> t : children) {
            t.setParent(this);
        }
        this.children.addAll(children);
    }

    private void setParent(Tree<T> parent) {
        this.parent = parent;
    }

    public Tree<T> getParent() {
        return parent;
    }

    public T getData() {
        return this.data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public boolean isRoot() {
        return (this.parent == null);
    }

    public boolean isLeaf() {
        return this.children.size() == 0;
    }

    public void removeParent() {
        this.parent = null;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) return true;
        if (object == null || getClass() != object.getClass()) return false;
        Tree<?> tree = (Tree<?>) object;
        return Objects.equals(children, tree.children) &&
                Objects.equals(data, tree.data);
    }

    @Override
    public int hashCode() {
        return Objects.hash(children, data);
    }
}

class BookTree extends Tree<Book> {

    public BookTree(Book data) {
        super(data);
    }

    public BookTree(Book data, Tree<Book> parent) {
        super(data, parent);
    }
}

「データ」と「子供」:あなたは私の実装から見ることができるように、私は2つのフィールドのみを使用しています。したがって、私の質問は、私は正確にメソッドの等号/ハッシュコードを実装するかどうか?間違った場合は、どのように示してください。

GhostCat敬礼モニカC.:

したがって、私の質問は、私は正確にメソッドの等号/ハッシュコードを実装するかどうか?

まず第一に:「何が正しいのですか?」ツリーが実装すべき理由... 1は不思議でしたequals()し、hashCode()最初の場所で。特にhashCode()トリッキーです:あなたは、HashMapの/ HashSetの内の対応するオブジェクトを格納することができるので、この方法のポイントは、(主に)です。しかし、それは大きな赤い旗を上げる:これらのクラスは何の両方でないとき、それのようにhashCode()戻って別の値経時。そして、それはあなたのコードが実行されます正確に何である:あなたのツリーを変更するたびに(ノードの追加/削除)を、hashCode()異なる結果が得られます。

だから我々は、標準ライブラリは何を見ている可能性があり:そして、私たちはそこに見つけるJTreeの両方のメソッドを実装していません...!私たちが目を向けるとき、一方、AbstractSet(TreeSetのための基底クラスである)、私たちはそこに両方のメソッドが実装されていることを見つけて、メンバーが含まれます。だから、両方の方法が有効であると思われます。

本当にあなたはどのように依存します:質問に戻って来たい仕事にこれらの2つの方法を。2つのツリーは、彼らが完全に同じ内容を持っているとき、同じである(意味:子供の順序は重要ではありませんか)?

長い話を短く:あなたはすべてのことを確実にしたいと仮定して、データが等しく、すべてのことを子供たちが等しく、同じ順序で、その後、あなたの実装が正しいようです。

はい、その制限のみこれら二つの属性をチェックするには、多くの意味を作る:あなたは親のリンクが含まれている場合、あなたはすぐに破られることができない再帰に入ります。

最後に:あなたはJUnitを用いたこの質問をタグ付け。これは、あなたの製品コードのテストを書いて検討することを意味します。そして、これらのテストは、あなたの質問に答える必要があります。意味:1つのアプローチは、あなたが座っていることでしょう定義するこれらの2つの方法の契約を。そして、あなたはテストケースの数作成確認するこれらの契約のすべての側面を。そして、あなたのテストケースは、あなたの製品コードは、あなたの契約を満たしているかどうかを教えてくれ。

実装方法/場合を教えてくれる普遍的なルールはありません。私はここで重要なポイントだと思うequals()し、hashCode()Treeクラスのために。あなたはそれを行う方法/場合は、あなたの要件を検討する必要があります。そして、あなたは、あなたが与えられた実装が必要条件/契約を満たしているかどうかを確認するために適用され、その知識からテストを導き出します。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=236318&siteId=1