良い本との呼び声高かったので、Java復習を兼ねて読んだ。
スッキリわかる Java入門 実践編 第2版 (スッキリシリーズ)
確かに良い本だと思います。これまでなんとなく知ってた事なども一通り整理できた。章立てとか、話の順番も素晴らしく整理されていて、最後までさくさく読める。
以下、理解があやふやだった点を中心に覚書。(一部だけだが・・・)
toString() / equals() / hashCode()のオーバーライドについて
第1部 第4章
classを作成した時は、これらのメソッドをオーバーライドしないと、コレクションが正しく動作しない場合がある。
例えば
ArrayList#remove()
内部でequals()を呼んで等価判定を行っているため、正しく動かなくなる。ただし、等価判定されることが明らかに不要なクラスではオーバーライドの必要はない(データではないクラス)
HashSet, HashMap, HashTable
equals()メソッドはコストが高いため、常に実施するわけではない。hashCode()を使って効率的に比較している。だからオーバーライドは必須です。
- toString()
文字出力しとく。 - equals()
等価であることを保証する。開発者が正しいと考える等価判定アルゴリズムをJVMに伝えることが目的 - hashCode()
等価であるインスタンスからは必ず同じハッシュ値を返す。異なるインスタンスからはなるべく異なるようにする。
public class Employee {
private String name;
private int age;
private String address;
...
public String toString() {
return "名前:" + this.name + "年齢:" + this.age
+ "住所" + this.address;
}
public boolean equals(Object o) {
if (o == this) return true;
if (o == null) retrun false;
if (!(o instanceof Employee)) return false;
Employee r = (Employee) o;
if (!this.name.trim().equals(r.name.trim())) return false;
if (!this.age.equals(r.age)) return false;
if (!this.address.trim().equals(r.address.trim())) return false;
return true;
}
public int hashCode() {
int result = 11; // 0以外の適当な値
result = result * 31 + name.hashCode(); // 奇数かつ素数
result = result * 31 + age;
result = result * 31 + address.hashCode();
return result;
}
}
このあたりはEffective Javaでも数ページ割いて説明されています。
reflectionについて
第1部 第7章
リフレクションを使うと、アクセス制御(private/protected/...)を無視してメンバを利用することができる。
シリアライズ
第2部 第10章
例えばインスタンスをそのままファイルに保存するときにシリアライズする。
public class Employee implements Serializable {
....
}
public class Main {
public static void main(String[] args) throws Exception {
Employee employee1 = new Employee();
// Save
FileOutputStream fos = new FileOutputStrem("c:¥¥data.dat");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(employee1);
oos.flush();
oos.close();
// Restore
FileInputStream fis = new FileInputStream("c:¥¥data.dat");
ObjectInputStream ois = new ObjectInputStream(fish);
Employee employee2 = (Employee)ois.readObject();
ois.close();
}
}
注意点
- Serializableを実装してないフィールドは直列化されない。そのフィールドは復元時nullになる。
- Staticのフィールドは対象にならない
- transientで修飾したフィールドは対象にならない