SlideShare a Scribd company logo
1 of 29
Effective Java 輪読会 第2回
(項目8~10)
2013/12/04
開発部 野口
項目8 equalsをオーバーライドす
る時は一般契約に従う
一般契約
• 一般契約に従うことは、それらのメソッ
ドをオーバーライドするクラスの責任
equalsをオーバーライドしないのが
正しいとき(1/2)
• クラスの個々のインスタンスは、本質的
に一意である
– 例)Threadクラス

• 「論理的等価性」検査を、クラスが提供
するかどうかに関心がない
– 例)java.util.Randomクラス
equalsをオーバーライドしないのが
正しいとき(2/2)
• スーパークラスがすでにequalsをオーバー
ライドしており、スーパークラスの振る
舞いがこのクラスに対して適切である
– 例)AbstractSetとほとんどのSet、AbstractList
とList、AbstractMapとMap

• クラスがprivateあるいはパッケージプライ
ベートであり、そのequalsメソッドが決し
て呼び出されないことが確かである
– その場合、呼び出されないことをアサートす
べき
equalsをオーバーライドするのが
適切なとき
• クラスが論理的等価性という概念を持っ
ている
• スーパークラスが(そのクラスが必要と
する振る舞いを実装するために)equalsを
オーバーライドしていない
• 一般に、値クラスの場合
– 例)Integer、Date
enumのequalsは
オーバーライドする必要がない
• 個々の値に対してたかだか1つのオブジェクトし
か存在しないため
– 論理的等価性とオブジェクトの同一性が一致
する
equalsメソッドの一般契約
•
•
•
•
•

反射的
対称的
推移的
整合的
非null
反射性
• 普通に実装すれば自然とそうなります
対称性
• 簡単に破ってしまうことがある!
– pp.35- StringとCaseInsensitiveStringの例
推移性
• これも簡単に破ってしまうことがある!
– pp.36- PointとColorPointの例

★インスタンス化可能なクラスを拡張して、
equals契約を守ったまま値要素を追加する方法は
ない
→じゃあどうするの?
推移性を保つ
• instanceofのかわりにgetClassを用いる?
– LSP違反!(pp.38- CounterPointの例)

• 継承ではなくコンポジションを用いる
– 解決(pp.39- ColorPointの例)
– See also: 項目16 継承よりコンポジションを選
びなさい
★リスコフの置換原則(Liscov Substitution Principle:
LSP)
「派生型はその基本型と交換可能でなければならな
注意
• java.sql.Timestampは対称性を守っていない
(悪い)例!
– ドキュメントに注意書きもあるが、誤用して
もコンパイルエラーにはならない
• デバッグが困難になる

• 抽象クラスの継承においては、これらの
問題は起こらない
– See also: 項目20 タグ付クラスよりクラス階層
を選ぶ
整合性
• 不変オブジェクトのequalsは常に一貫性の
ある値を返すようにする
– 疑問:「意図せず、そうではなくなってしま

う」ケースがあるか?
→むしろ「不変オブジェクトにして、整合性
を確保することを検討すべき」ということが
主眼
→「信頼できないリソース」に依存するとそ
うなりうる!
非null性
• nullとの比較でNullPointerExceptionをス
ローしない
• かわりにfalseを返す
• 明示的なnullチェックは不要で、instanceof
で十分
まとめ:
高品質なequalsのための処方箋
• 自分自身かどうかを検査するために、ま
ず==を用いる
• 引数の型の正しさを検査するために、
instanceofを用いる
• 引数を正しい型にキャストする
• 「意味のある」フィールドについて、一
致を検査する
• 対称性、推移性、整合性をテストする
補足説明
• equalsをオーバーライドするときは、常に
hashCodeをオーバーライドする(項目9)
• あまりにも賢くなろうとしない
– 例)Fileクラスは、同じファイルを参照してい
るシンボリックリンクを等しいとは見なさな
い

• equals宣言中のObjectを他の型で置き換え
ない
– この問題を防ぐため、@Overrideを用いよう
項目9 equalsをオーバーライドすると
きは、常にhashCodeをオーバーライ
ドする
hashCodeメソッドの一般契約
• アプリケーション実行中、equalsについて
変化していないオブジェクトのhashCode
は常に同じ整数を返す
• equalsについて等しい2つのオブジェクト
のhashCodeは同じ整数を返す
• equalsについて等しくない2つのオブジェ
クトのhashCodeが別々の整数を返す必要
はない
– ただし、ハッシュテーブルのパフォーマンス
に影響しうる
hashCodeをオーバーライドするの
を
忘れた場合

• 「等しいオブジェクトは、同じハッシュ
コードを持つ」という契約が破られる
• equalsで等しくても、別のオブジェクトな
ので、デフォルトのhashCodeは別々の値
を返す
– 例)pp.45- PhoneNumberクラス
hashCodeの実装
• (正当だが)最悪な実装
@Override public int hashCode() { return 42; }

• 良い実装の簡単な処方箋
– pp.47を参照
★Eclipseには、項目8~9の指針に概ね沿ったequalsと
hashCodeの自動生成機能があるようです
- http://hysa.hateblo.jp/entry/20101108/1289223367
hashCodeの実装(補足)
(1/2)
• 主にハッシュキーとして使用されるよう
なオブジェクトであれば、ハッシュコー
ドのキャッシュを検討する
– インスタンス生成時
– 遅延初期化

• 「パフォーマンス向上のため」として、
意味のあるフィールドを計算から除外し
てはいけない
– 失敗例)Javaのリリース1.2より古いString
hashCodeの実装(補足)
(2/2)
• hashCodeの詳細を公開すべきではない
– 将来より良いハッシュ関数を適用することの
妨げになる
項目10 toStringを常にオーバーラ
イドする
toStringメソッドの一般契約
• 簡潔だが、人が読みやすくなっている有
益な表現
• すべてのサブクラスがこのメソッドを
オーバーライドすることを推奨する
toStringメソッドの実装
• 実用的な場合には、オブジェクトに含ま
れる興味がある情報をすべて返す
• すべて返すのが実用的でない場合、要約
を返す
– それ自身で意味が自明であるのが理想
• ○ Manhattan white pages (1487536 listings)
• △ Thread[main,5,main]
toStringメソッドのドキュメンテー
ション(1/3)
• 形式を明示する
– ○ 標準的で曖昧さがなく、可読性があるオブ
ジェクトの表現形式を提供できる
– ○ Stringを引数とするファクトリメソッド/コ
ンストラクタを提供できる
– ✕ 形式を変更できなくなる
toStringメソッドのドキュメンテー
ション(2/3)
• 形式を明示しない
– ○ 形式を変更できる
– △ 形式を明示する場合のメリット(○)は得
られない
toStringメソッドのドキュメンテー
ション(3/3)
• 形式を明示するか否かにかかわらず、意
図は明確にする
• 形式を明示するか否かにかかわらず、
toStringに含まれる情報へのアクセサを提
供する

More Related Content

More from Appresso Engineering Team

マルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded Executionマルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded ExecutionAppresso Engineering Team
 
JavaScript 勉強会 ― 変数・演算子・文
JavaScript 勉強会 ― 変数・演算子・文JavaScript 勉強会 ― 変数・演算子・文
JavaScript 勉強会 ― 変数・演算子・文Appresso Engineering Team
 
Effective Java 輪読会 第7章 項目41-42
Effective Java 輪読会 第7章 項目41-42Effective Java 輪読会 第7章 項目41-42
Effective Java 輪読会 第7章 項目41-42Appresso Engineering Team
 
Effective Java 輪読会 第7章 項目38-40
Effective Java 輪読会 第7章 項目38-40Effective Java 輪読会 第7章 項目38-40
Effective Java 輪読会 第7章 項目38-40Appresso Engineering Team
 
Effective Java 輪読会 第6章 項目35-37
Effective Java 輪読会 第6章 項目35-37Effective Java 輪読会 第6章 項目35-37
Effective Java 輪読会 第6章 項目35-37Appresso Engineering Team
 
Effective java 輪読会 第6章 項目32-34
Effective java 輪読会 第6章 項目32-34Effective java 輪読会 第6章 項目32-34
Effective java 輪読会 第6章 項目32-34Appresso Engineering Team
 
Effective java 輪読会 第6章 項目30-31
Effective java 輪読会 第6章 項目30-31Effective java 輪読会 第6章 項目30-31
Effective java 輪読会 第6章 項目30-31Appresso Engineering Team
 
Effective java 輪読会 第5章 項目26-29
Effective java 輪読会 第5章 項目26-29Effective java 輪読会 第5章 項目26-29
Effective java 輪読会 第5章 項目26-29Appresso Engineering Team
 
Effective java 輪読会 第5章 項目23-25
Effective java 輪読会 第5章 項目23-25Effective java 輪読会 第5章 項目23-25
Effective java 輪読会 第5章 項目23-25Appresso Engineering Team
 
Effective java 輪読会 第4章 項目18-22
Effective java 輪読会 第4章 項目18-22Effective java 輪読会 第4章 項目18-22
Effective java 輪読会 第4章 項目18-22Appresso Engineering Team
 

More from Appresso Engineering Team (20)

マルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded Executionマルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded Execution
 
JavaScript 勉強会 ― 変数・演算子・文
JavaScript 勉強会 ― 変数・演算子・文JavaScript 勉強会 ― 変数・演算子・文
JavaScript 勉強会 ― 変数・演算子・文
 
JavaScript 勉強会 ― 型と値
JavaScript 勉強会 ― 型と値JavaScript 勉強会 ― 型と値
JavaScript 勉強会 ― 型と値
 
Effective Java 輪読会 項目69-70追加
Effective Java 輪読会 項目69-70追加Effective Java 輪読会 項目69-70追加
Effective Java 輪読会 項目69-70追加
 
Effective Java 輪読会 項目69-70
Effective Java 輪読会 項目69-70Effective Java 輪読会 項目69-70
Effective Java 輪読会 項目69-70
 
Effective Java 輪読会 項目66-68
Effective Java 輪読会 項目66-68Effective Java 輪読会 項目66-68
Effective Java 輪読会 項目66-68
 
Effective Java 輪読会 項目71-73
Effective Java 輪読会 項目71-73Effective Java 輪読会 項目71-73
Effective Java 輪読会 項目71-73
 
Java Day Tokyo 2014 まとめ (chen)
Java Day Tokyo 2014 まとめ (chen)Java Day Tokyo 2014 まとめ (chen)
Java Day Tokyo 2014 まとめ (chen)
 
Effective Java 輪読会 項目63-65
Effective Java 輪読会 項目63-65Effective Java 輪読会 項目63-65
Effective Java 輪読会 項目63-65
 
Effective Java 輪読会 項目60-62
Effective Java 輪読会 項目60-62Effective Java 輪読会 項目60-62
Effective Java 輪読会 項目60-62
 
Effective java 輪読会 項目57-59
Effective java 輪読会 項目57-59Effective java 輪読会 項目57-59
Effective java 輪読会 項目57-59
 
Effective Java 輪読会 項目53-56
Effective Java 輪読会 項目53-56Effective Java 輪読会 項目53-56
Effective Java 輪読会 項目53-56
 
Effective Java 輪読会 第7章 項目41-42
Effective Java 輪読会 第7章 項目41-42Effective Java 輪読会 第7章 項目41-42
Effective Java 輪読会 第7章 項目41-42
 
Effective Java 輪読会 第7章 項目38-40
Effective Java 輪読会 第7章 項目38-40Effective Java 輪読会 第7章 項目38-40
Effective Java 輪読会 第7章 項目38-40
 
Effective Java 輪読会 第6章 項目35-37
Effective Java 輪読会 第6章 項目35-37Effective Java 輪読会 第6章 項目35-37
Effective Java 輪読会 第6章 項目35-37
 
Effective java 輪読会 第6章 項目32-34
Effective java 輪読会 第6章 項目32-34Effective java 輪読会 第6章 項目32-34
Effective java 輪読会 第6章 項目32-34
 
Effective java 輪読会 第6章 項目30-31
Effective java 輪読会 第6章 項目30-31Effective java 輪読会 第6章 項目30-31
Effective java 輪読会 第6章 項目30-31
 
Effective java 輪読会 第5章 項目26-29
Effective java 輪読会 第5章 項目26-29Effective java 輪読会 第5章 項目26-29
Effective java 輪読会 第5章 項目26-29
 
Effective java 輪読会 第5章 項目23-25
Effective java 輪読会 第5章 項目23-25Effective java 輪読会 第5章 項目23-25
Effective java 輪読会 第5章 項目23-25
 
Effective java 輪読会 第4章 項目18-22
Effective java 輪読会 第4章 項目18-22Effective java 輪読会 第4章 項目18-22
Effective java 輪読会 第4章 項目18-22
 

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