Effective java 輪読会 第3章 項目8,9,10

29
Effective Java 輪輪輪 輪 2 輪輪 8 10 2013/12/04 輪輪輪 輪輪

description

3章 項目8,9,10

Transcript of Effective java 輪読会 第3章 項目8,9,10

Page 1: Effective java 輪読会 第3章 項目8,9,10

Effective Java 輪読会 第 2 回(項目 8 ~ 10 )

2013/12/04

開発部 野口

Page 2: Effective java 輪読会 第3章 項目8,9,10

項目 8 equalsをオーバーライドする時は一般契約に従う

Page 3: Effective java 輪読会 第3章 項目8,9,10

一般契約• 一般契約に従うことは、それらのメソッ

ドをオーバーライドするクラスの責任

Page 4: Effective java 輪読会 第3章 項目8,9,10

equals をオーバーライドしないのが正しいとき (1/2)

• クラスの個々のインスタンスは、本質的に一意である– 例) Thread クラス

• 「論理的等価性」検査を、クラスが提供するかどうかに関心がない– 例) java.util.Random クラス

Page 5: Effective java 輪読会 第3章 項目8,9,10

equals をオーバーライドしないのが正しいとき (2/2)

• スーパークラスがすでに equals をオーバーライドしており、スーパークラスの振る舞いがこのクラスに対して適切である– 例) AbstractSet とほとんどの Set 、 AbstractList

と List 、 AbstractMap と Map• クラスが private あるいはパッケージプライ

ベートであり、その equals メソッドが決して呼び出されないことが確かである– その場合、呼び出されないことをアサートすべき

Page 6: Effective java 輪読会 第3章 項目8,9,10

equals をオーバーライドするのが適切なとき

• クラスが論理的等価性という概念を持っている

• スーパークラスが(そのクラスが必要とする振る舞いを実装するために) equals をオーバーライドしていない

• 一般に、値クラスの場合– 例) Integer 、 Date

Page 7: Effective java 輪読会 第3章 項目8,9,10

enum の equals はオーバーライドする必要がない

• 個々の値に対してたかだか 1 つのオブジェクトしか存在しないため– 論理的等価性とオブジェクトの同一性が一致

する

Page 8: Effective java 輪読会 第3章 項目8,9,10

equals メソッドの一般契約• 反射的• 対称的• 推移的• 整合的• 非 null

Page 9: Effective java 輪読会 第3章 項目8,9,10

反射性• 普通に実装すれば自然とそうなります

Page 10: Effective java 輪読会 第3章 項目8,9,10

対称性• 簡単に破ってしまうことがある!– pp.35- String と CaseInsensitiveString の例

Page 11: Effective java 輪読会 第3章 項目8,9,10

推移性• これも簡単に破ってしまうことがある!– pp.36- Point と ColorPoint の例

★ インスタンス化可能なクラスを拡張して、 equals 契約を守ったまま値要素を追加する方法はない →じゃあどうするの?

Page 12: Effective java 輪読会 第3章 項目8,9,10

推移性を保つ• instanceof のかわりに getClass を用いる?– LSP 違反!( pp.38- CounterPoint の例)

• 継承ではなくコンポジションを用いる– 解決( pp.39- ColorPoint の例)– See also: 項目 16 継承よりコンポジションを選び

なさい

★ リスコフの置換原則( Liscov Substitution Principle: LSP )   「派生型はその基本型と交換可能でなければならない」

Page 13: Effective java 輪読会 第3章 項目8,9,10

注意• java.sql.Timestamp は対称性を守っていない

(悪い)例!– ドキュメントに注意書きもあるが、誤用して

もコンパイルエラーにはならない• デバッグが困難になる

• 抽象クラスの継承においては、これらの問題は起こらない– See also: 項目 20 タグ付クラスよりクラス階

層を選ぶ

Page 14: Effective java 輪読会 第3章 項目8,9,10

整合性• 不変オブジェクトの equals は常に一貫性

のある値を返すようにする– 疑問:「意図せず、そうではなくなってしま

う」ケースがあるか? →むしろ「不変オブジェクトにして、整合性

を確保することを検討すべき」ということが主眼

 →「信頼できないリソース」に依存するとそうなりうる!

Page 15: Effective java 輪読会 第3章 項目8,9,10

非 null 性• null との比較で NullPointerException をス

ローしない• かわりに false を返す• 明示的な null チェックは不要

で、 instanceof で十分

Page 16: Effective java 輪読会 第3章 項目8,9,10

まとめ:高品質な equals のための処方箋

• 自分自身かどうかを検査するために、まず == を用いる

• 引数の型の正しさを検査するために、 instanceof を用いる

• 引数を正しい型にキャストする• 「意味のある」フィールドについて、一致

を検査する• 対称性、推移性、整合性をテストする

Page 17: Effective java 輪読会 第3章 項目8,9,10

補足説明• equals をオーバーライドするときは、常に

hashCode をオーバーライドする(項目 9 )• あまりにも賢くなろうとしない– 例) File クラスは、同じファイルを参照してい

るシンボリックリンクを等しいとは見なさない• equals 宣言中の Object を他の型で置き換え

ない– この問題を防ぐため、 @Override を用いよう

Page 18: Effective java 輪読会 第3章 項目8,9,10

項目 9 equalsをオーバーライドするときは、常に hashCodeをオーバーライドする

Page 19: Effective java 輪読会 第3章 項目8,9,10

hashCode メソッドの一般契約• アプリケーション実行中、 equals について

変化していないオブジェクトの hashCode は常に同じ整数を返す

• equals について等しい 2 つのオブジェクトの hashCode は同じ整数を返す

• equals について等しくない 2 つのオブジェクトの hashCode が別々の整数を返す必要はない– ただし、ハッシュテーブルのパフォーマンスに影響しうる

Page 20: Effective java 輪読会 第3章 項目8,9,10

hashCode をオーバーライドするのを忘れた場合

• 「等しいオブジェクトは、同じハッシュコードを持つ」という契約が破られる

• equals で等しくても、別のオブジェクトなので、デフォルトの hashCode は別々の値を返す– 例) pp.45- PhoneNumber クラス

Page 21: Effective java 輪読会 第3章 項目8,9,10

hashCode の実装• (正当だが)最悪な実装

• 良い実装の簡単な処方箋– pp.47 を参照

★Eclipse には、項目 8 ~ 9 の指針に概ね沿った equalsと hashCode の自動生成機能があるようです  - http://hysa.hateblo.jp/entry/20101108/1289223367

@Override public int hashCode() { return 42; }

Page 22: Effective java 輪読会 第3章 項目8,9,10

hashCode の実装(補足)( 1/2 )

• 主にハッシュキーとして使用されるようなオブジェクトであれば、ハッシュコードのキャッシュを検討する– インスタンス生成時–遅延初期化

• 「パフォーマンス向上のため」として、意味のあるフィールドを計算から除外してはいけない–失敗例) Java のリリース 1.2 より古い String

Page 23: Effective java 輪読会 第3章 項目8,9,10

hashCode の実装(補足)( 2/2 )

• hashCode の詳細を公開すべきではない–将来より良いハッシュ関数を適用することの妨げになる

Page 24: Effective java 輪読会 第3章 項目8,9,10

項目 10 toStringを常にオーバーライドする

Page 25: Effective java 輪読会 第3章 項目8,9,10

toString メソッドの一般契約• 簡潔だが、人が読みやすくなっている有益な表現

• すべてのサブクラスがこのメソッドをオーバーライドすることを推奨する

Page 26: Effective java 輪読会 第3章 項目8,9,10

toString メソッドの実装• 実用的な場合には、オブジェクトに含ま

れる興味がある情報をすべて返す• すべて返すのが実用的でない場合、要約を

返す– それ自身で意味が自明であるのが理想• ○ Manhattan white pages (1487536 listings)• △ Thread[main,5,main]

Page 27: Effective java 輪読会 第3章 項目8,9,10

toString メソッドのドキュメンテーション( 1/3 )

• 形式を明示する–○ 標準的で曖昧さがなく、可読性があるオブ

ジェクトの表現形式を提供できる– ○ String を引数とするファクトリメソッド/コ

ンストラクタを提供できる– ✕ 形式を変更できなくなる

Page 28: Effective java 輪読会 第3章 項目8,9,10

toString メソッドのドキュメンテーション( 2/3 )

• 形式を明示しない–○ 形式を変更できる–△ 形式を明示する場合のメリット(○)は得

られない

Page 29: Effective java 輪読会 第3章 項目8,9,10

toString メソッドのドキュメンテーション( 3/3 )

• 形式を明示するか否かにかかわらず、意図は明確にする

• 形式を明示するか否かにかかわらず、 toString に含まれる情報へのアクセサを提供する