Effective Javaを読んでいる⑧

Object.equalsの適切なオーバーライド

オーバーライドしなくていいのは・・・

  1. インスタンスが本質的にユニークである場合(コネクションとか?)
  2. 論理的に等しいかどうかがどうでもいい場合(よくわからん)
  3. スーパークラスがequalsを実装してて継承したクラスもそのequalsで問題ない場合
  4. equalsを絶対に呼ばない場合 2と4の違いがよくわからん

Enumが==で比較できるのは1に当てはまるんだな

☆equalsのおやくそく(Object (Java Platform SE 7))☆

  1. xがnullでない場合、x.equals(x)はtrueを返却する。
  2. xとyがnull出ない場合、x.equals(y)がtrueを返却するのであれば、y.equals(x)もtrueを返却する。
  3. x.equals(y)がtrueでy.equals(z)がtrueならx.equals(z)もtrueを返却する。
  4. 値が変わってない限り、毎回おんなじtrueかfalseを返却する。
  5. xがnullでない場合、x.equals(null)はfalseとなる。

John Donne
John Donne の "No man is an island"とはどんな意味です... - Yahoo!知恵袋
孤立したクラスなど無い
→equalsの約束を破るとその約束に従って他のクラスがなんかした時めちゃくちゃになりますよ、みたいな

equalsの引数をObjectクラスにする意味ってなんなんだろって思ったけど継承してるからでした 脳細胞が全て死んでいる 自分自身の型をジェネリクスのEみたいな感じで表せないんだろうか

instanceofの動作をおもいっきり勘違いしてた
public class Kani {
    public static void main(String [] args){
        Kogani k = new Kogani();//ここはtrue
        System.out.println(k instanceof Kani);
        
        Kani k2 = new Kani();//ここはfalse
        System.out.println(k2 instanceof Kogani);
    }
}


class Kogani extends Kani{
    
}

Equality, Relational, and Conditional Operators (The Java™ Tutorials > Learning the Java Language > Language Basics)

同じクラスの場合 → true
親クラスと比較 → true
小クラスと比較 → false
実装しているインターフェースと比較 → true
Interface a = new Class(); こんなかんじで代入できるかどうかと同じ基準?
常に同じクラスの場合だけtrueだと思ってたけどそもそもなまえがinstanceofだなあっていう

getClassってなんだ

ClassのClassを調べるときどうしたらいいんだろうと思ってClass Classで検索したらAPIが出てきた。
とりあえずクラスを表してるんだな。そして同じクラスに対してgetClassを呼び出すと常に同じインスタンスが帰ってくるんだな。

liskov substitution principleってなんだ

リスコフの置換原則
サブクラスはスーパークラスとしても正しく動かなければならないみたいな
参考:オブジェクト思考: リスコフの置換原則

要するにequalsの実装にインスタンスの実装クラスが等しいかどうかを依存させると親クラスと継承クラスでequalsがちゃんと動かない(絶対falseになる)からリスコフの置換原則に違反するってことなんだな。

じゃあどうしたらいいのか

コンポジションを使う

URLクラスはhashcodeを呼び出すと名前解決する

名前解決の結果が変わるとURL同じでもequalsでfalseがかえってくる java.net.URLの闇 - blog.scheakur.com

Equalsのレシピ

  1. ==で参照を比較する。 特に比較そのもののコストが高い場合にはとてもイケている。
  2. 引数の型チェックにはinstanceofを使う
  3. キャストする。
  4. フィールドを比較する。

FloatのNaNてなんだ

[http://sjc-p.obx21.com/word/en/nan.html:title]
    public static void main(String[] args) {
        Float f1 = 0f;
        Float f2 = 0f;
        
        Float r = f1/f2;
        System.out.println(r);
    }

これが0除算で例外投げられない事情がわからん JAVAの演算子に関して質問です。 整数を0で割ると、例外Arithmet… - 人力検索はてな 0ではないけどFloatの桁数では0としか表現できない的なやつ?

フィールドを比較する順番によってパフォーマンスに影響がある
→なるべく違うやつから比較すれば比較回数が少ない
当たり前だけどあんまり意識したことねーや

  1. あってんのか確認する。 Synmetric,transitive,consistent
    ちゃんと単体テストしようねっていう

・xとyがnull出ない場合、x.equals(y)がtrueを返却するのであれば、y.equals(x)もtrueを返却する。
・x.equals(y)がtrueでy.equals(z)がtrueならx.equals(z)もtrueを返却する。
・値が変わってない限り、毎回おんなじtrueかfalseを返却する。

リストの間になんか挟むと数字がリセットされるぞ

その他注意事項?

hashCodeをオーバーライドしなさい
賢く(複雑に)しすぎない
ちゃんとオーバーライドする(引数を独自の宣言にしない)
ちゃんとオーバーライドするときは@Overrideアノテーションを付ける