2008年4月アーカイブ

20080518追記:
tombloo依存解消版作った

Tumblrの仕様変更により、前回作ったパッチが事実上死んでしまわれたので、kuさんとこの微妙に新しくなったtumblrでReblogCommandを動くようにするためのパッチを利用してprivate postできるようにした。前回同様、yキーでprivate post。

リンク先にあるパッチ適用後のReblogCommandはtombloo側にurl情報を送り、後はtombloo側が頑張ってるようなので、ReblogCommandとtombloo両方にパッチをあてることにする。

リンク先にあるパッチ適用済みReblogCommandとprivate post機能を追加したReblogCommandとの相違点は以下の通り。(patch_file)

このパッチを適用したReblogCommandはこちらから。
んで最初の方に書いたように今回の場合、ReblogCommnadの修正だけではダメであり、tomblooを経由しているので、tombloo側にも修正が必要となる。

まずはbrowser.xulの修正。
extensions/tombloo/chrome/content/browser.xul
win環境だと特に設定をしていなければ、C:\Documents and Settings\USER_NAME\Application Data\Mozilla\Firefox\Profiles\XXXXXXXX.default\extensions \tombloo@brasil.to\chrome\contentにある。

privateReblog を追加するだけ。
最後にtombloo本体を弄る。

extensions/tombloo/chrome/content/library/
に20_Tumblr.jsというファイルがあるのでコレに以下のパッチを適用させる。(パッチ当てる前にバックアップとっておいたほうがイイかも。)

パッチ適用後のファイルはこちら。(.js以降は削除)
激しくコピペ(´A`) 我ながら情けないパッチだのぅ。

とりあえずTombloo0.1.6で動作確認済。privateモードも活用してる方は自己責任でどうぞー。

前回からの続き。

1日2項目ペースのつもりで...と考えていたのに早くも乱れ気味です。誕生日迎える前には読み終わりたいところだ。
項目6までは以前読んだことがあるのですんなりといけたが、こっから先が大変そう...。

3章はすべてのオブジェクトに共通のメソッド ってことですべてのクラスの親に当たるObjectにあるメソッドの話がメイン。

---
7.equals()オーバライド時の注意点

-どんな時にオーバライドするの?
 →参照が同じかどうかではなく、参照先の中身が同じかどうか(論理的等価性)を知る必要があり、親クラスで使えそうな実装がされていないとき。

-equals()は好き勝手に書いちゃダメ。

Objectのリファレンスから引用

equals メソッドは、null 以外のオブジェクト参照での同値関係を実装します。
* 反射性 (reflexive):null 以外の参照値 x について、x.equals(x) は true を返す
* 対称性 (symmetric):null 以外の参照値 x と y について、x.equals(y) は、y.equals(x) が true を返す場合だけ true を返す
* 推移性 (transitive):null 以外の参照値 x、y、z について、x.equals(y) が true を返し、かつ y.equals(z) が true を返す場合に、x.equals(z) は true を返す
* 整合性 (consistent):null 以外の参照値 x および y について、x.equals(y) を複数呼び出すと常に true を返すか、常に false を返す。 これは、オブジェクトに対する equals による比較で使われた情報が変更されていないことが条件である
* null でない任意の参照値 x について、x.equals(null) は false を返す(*)
(*)...本ではこの項目を非null性と名付けている。

上の3つは大学の数学でもでてくる反射律、対称律、推移律だね。なつかすぃ。
本ではこの中でも特に対称性と推移性が守られていない例を紹介している。
結論としてはインスタンス化可能なクラスを継承してフィールドを追加した子クラスを作り、拡張した場合、厳密なequals()は実装できない。(親と子を比較しようとするとおかしなことになる。)これは本のコード例を見た方が早い(p28~30)。
解決方法としてコンポジットを使う例が紹介されている(p31)。

-非null性のチェックにnullチェックはしない。型チェックでnullも一緒にはじく。if(!(obj instanceof Hoge)) return false;
ここまで読んで昔GAのプログラムを作っていたときに遺伝子クラスにequals(Gene gene)って書いてたなぁと思い出す。正しくはequals(Object obj)だよなぁ。(この項の最後の方でも同様のことについて触れている。これはオーバライドじゃなく、オーバロードだ!)どんな型でもequalsに突っ込めるようにするのが正しい。

(p32) -くおりてぃーの高いequals()の作り方のまとめ
 1.自分自身かどうかを==で判定(反射性) →親クラスにequals実装がなければObjectのequalsがそのまま使える。
 2.型検査(instanceof使って)そのままキャスト
 3.2つのフィールドの一致検査(比較する順番にも注意する。なるべく評価コストが小さく、2つのオブジェクト間で異なりそうなものから比較すればパフォーマンスが良くなる。)

doubleとfloatの比較の注意点が書かれている。DoubleやFloatクラスのリファレンスにも同様のことが載っている。

System.out.println(0.0 == -0.0);//true

System.out.println(Double.doubleToLongBits(0.0) == Double.doubleToLongBits(-0.0));//false

これしらんかった(;´Д`)
でもここまで気にする必要あるんかいな?(フィールドにdoubleを滅多に使わない人の一意見)

 4.対象性、推移性、整合性を最後にテスト
(アレ?残りは?→㌧でもない実装をしない限り残りの2つは満たされているはず)

-項目の最後に捕捉説明
 -equals上書きしたらhashCodeも上書き(次項目)
 -賢すぎる実装はしない
 -信頼できない外部リソースに依存するequalsは作らない 悪例)java.net.URL#equals() 整合性に欠けるって話だね。


--------------
8.equals上書きしたらhashCodeも上書き
全然しらんでした....( ;´Д`)

再びObjectクラスのリファレンスより引用

hashCode メソッドの一般的な規則を次に示します。
* Java アプリケーションの実行中に同じオブジェクト上で複数回呼び出される場合は必ず、このオブジェクトに対する equals による比較で使われた情報が変更されていなければ、hashCode メソッドは同じ整数を一貫して返さなければならない。ただし、この整数は同じアプリケーションの実行ごとに同じである必要はない
* equals(Object) メソッドで 2 つのオブジェクトが等価とされた場合、どちらのオブジェクトで hashCode メソッドを呼び出しても結果は同じ整数値にならなければならない
* equals(java.lang.Object) メソッドで 2 つのオブジェクトが等価でないとされた場合は、これらのオブジェクトに対して hashCode メソッドを呼び出したときに、結果が異なる整数値にならなくてもかまわない。しかし、等しくないオブジェクトについては異なる整数値が生成されるようにすれば、ハッシュテーブルのパフォーマンスを上げることができる
equalsを上書きして参照が違くても中身同じならtrueを返すような実装をした場合、hashCodeも同じ値を返すようにしないと2番目の規則に反することになってしまう。

-hashCode()に求められるモノ
 -意味的に同じオブジェクトは同じハッシュ値を返す
 -違うオブジェクトは異なるハッシュ値を均等に分散させて返す

これらが守られないとハッシュ系コレクションクラス利用時におかしな振る舞いをしてしまう。

p37で理想的なhashCode()を実装するためのガイドラインがstep形式でまとめられている。
この部分を読み終わった後、試しにStringのhashCodeの実装を見てみたが、ハッシュ値の計算部分が正にその通りになっていた。
更にStringではハッシュ値をデフォルト0でインスタンスフィールドに保持していて、0ならハッシュ計算。0以外ならそれを返す...といったようにキャッシュ化されていてもう少し賢い実装になっている。

-パフォーマンスよりもハッシュ値が重複しないように心がける。
 →Hashが複数のLinkListに化けてしまう恐れがある。

-Java1.2より前のString#hashCode()の黒歴史


--------------
9.toString()は常に上書き
まぁ、これは知ってた。特にdebug時に大活躍だよなぁ。

-ObjectのtoStringはクラス名@符合無し16進ハッシュ値なので読みづらいし、意味がない。

-toString()を上書きするならそのクラスのオブジェクトが含む意味のある情報を全て返すべき。→あまりに長くなるなら要約で。

-toString()ではきだした情報へのアクセサを作る。→じゃないとtoStringに依存する実装をされて後からフォーマットが変更できなくなる。

-ドキュメントにどういう意図で作ったのかも書く(まぁ、これはtoStringに限ったことではないが)
 フォーマットが変更されるのか、されないのかも書く。変更しないつもりならフォーマットの詳細も。


--------------
10.clone()の注意点
cloneも結構いい加減に考えていたけど色々と制約があるようです。

それにしてもこの節、あんまりまとまってなくて分かりづらい。前橋さんの[Java謎+落とし穴]でも似たような話があったけどそっちの方が分かり易かったな。

前提として親クラスが正しくcloneを実装していなければならない。(コンストラクタが使えないのでsuper.cloneを頼るしかない)
cloneを実装するときはマーカーインターフェースCloneable(スペルミス?仕様です)をimplementsしなくてはいけない。

実装クラスが
 -プリミティブか不変クラスの参照しかもたない→super.clone()だけでok
 -可変クラスのインスタンスを持つ→clone元と同じ参照を持つので問題アリ(cloneは浅いコピー。)

p46-48 深いコピー(deep copy)の話
-クラスに可変オブジェクトをfinalで持つインスタンスフィールドがある→それclone()実装無理。
-インスタンスフィールドに配列を持つ→配列のcloneも浅いコピーなので各要素もコピーするように書き換える必要があり。

-super.clone()を呼び出してから全てのフィールドを真っ白にしてそこからclone元と同じになるように再現していくという方法もあり(ただし、パフォーマンス低)

-cloneで複製中のオブジェクトに対してfinalでないmethodは呼ばない。オブジェクトの状態が作られる前にmethodが呼ばれる可能性がある(項目15。これもしらんかった~。)

実装時のまとめ
-Cloneableをimplementsして、publicでcloneを上書き(Object#cloneはprotected。外からは呼び出せない)。clone内でsuper.cloneを呼んで可変クラスのobj参照をそれのコピーへの参照(deep copy)に修正していく。(多分その可変クラスのcloneを呼ぶことになる)
-不変クラスやプリミティブは手を加えなくてもok(だから不変クラスにcloneなんていらない)。ただし、オブジェクト生成日時といったデータなら当然のごとく作り直しだ。

-clone実装したくない
 コピーの代替手段(コピーコンストラクタ)か複製手段を最初から提供しない。

-コピーコンストラクタ
public Hoge(Hoge hoge)
(自分自身のクラスが型の)一個の引数を受け取るコンストラクタ。第1項目でも出てきたstatic factory method等でも代用可。メリットとしてはcloneの規約に従わなくても良いので自由に実装できる。可変オブジェクトをfinalで持つインスタンスフィールドがあってもコンストラクタならナントカできる。

--------------
11.Comparableのimplement
そのクラスのインスタンスがnatural Oderingを持つ場合に実装する。
比較なのでequalsと似たような数学的性質を持たなければならない。

compareToはequalsと違ってClassCast or NullPointer Exceptionを発生させてもok。だから型検査はせずにキャストとして代入するだけでok。

...といってもjdk1.5以降、Comparableはgenericsを使用するようになったのでClassCastExceptionが発生するのはあんまないかもなぁ。

return (a-b);の形に注意。
これ、楽だからついやっちゃうんだけど、aとbの差が2^31-1のときにしか使えないのね。
aが+、bが-で、aとbの絶対値が大きいとオーバーフローするので注意する。


4章に進みます。

この間の花見もそうでしたが、最近バイトの元上司の方からお褒めの言葉を頂く機会があり、非常に嬉しく思っています。

右も左も分からぬペーペーの学生バイトであった自分が今、研修を受けつつ、別スレッドでEffectiveJavaなんぞを読んでる余裕があるのも 今まで居た2社に鍛えられたおかげだと思ってます。これらの経験がなければ今頃、必死にJavaの文法をヒィヒィ言いながら覚えてることでしょう。そもそも今の会社に内定を貰えたかすらも怪しいもんです。バイトでお世話になった方全員に感謝します。


----
とエラソーにいっても、自分の技術力はまだまだだと思ふ。
未だに自分が尊敬する人達の足下にも及んでないだろうし、技術書を読む度に世の中にはもっともっとすごい人達がいっぱいいるということを知る。もっと勉強せんとねぇ。技術も、技術以外の分野でも。

effective_java.jpg
てなわけで読み始めました。

けどこの本(以前にもチラッと書いたような気がするが...)おそらく原本が長文だらけなんだろうな。どうも日本語訳が馴染めない。気を抜くとすぐに分からなくなる。これは後々読み返しても再び理解し直すまでのコストがでかいなと感じたので、自分なりに解釈した内容を要点として箇条書き風にまとめていこうかなぁと思う。色々書きたいが、本の中身書きすぎてもそれはそれで問題なのが難しいところだ。むぅ。

当然、自分なりの解釈なので間違ってることもあるかもしれない。
違うよ。全然違うよ。と思った方はコメントやらトラバやらで指摘していただければ幸い。

---
1. staticなfactory methodのお話。
new Hoge();ではなくHoge.getInstance();でインスタンスを生成する手法のメリットとデメリットを挙げている。

メリット
-分かり易い名前を付けられる。コンストラクタに渡す引数が多いのは大抵分かりづらい状態になってる。
-コンストラクタに比べて柔軟にインスタンスが返せる。(ex.渡すパラメータによって動的に返すオブジェクトを変更, immutableやsingletonなクラスの場合、method内で使い回すような処理を入れたりとか。)

応用例が分かりづらかった。
返すオブジェクトのクラスをpublicにすることなく、APIで返せるってなんぞ?と思った。
これは実際の実装例を見た方が早い。Collections.synchronizedMapのソースとかマジお勧め。

デメリット
-staticなfactory method + (default | private)なコンストラクタ という合わせ技を使うと自由にサブクラス作れね→継承じゃなくコンポジット促すのでok
-他のstatic methodに埋もれがち。javadocだと目立たね
→命名規則を一般的なものにしてすぐ分かるように。
 *valueOf():このmethodに渡したパラメータと意味的に同じものを返す。Integer等のラッパークラス等に多い。
 *getIncetance():その他

staticなfactory methodかコンストラクタか?
→迷うなら素直にコンストラクタで。

後、Immutableクラス(不変クラス)のインスタンス比較は.equals()じゃなく==でおk というのは目から鱗が落ちた。そらそうか。

--------------
2.singletonなクラスの作り方。
singletonについてはググれば大量に情報が出てくるので割愛。

知らなかったのはsingletonを直列化するときはsingletonクラス内でreadResolve()を実装する必要があるという部分。readResolve()内で唯一のインスタンスを返すコードを書く。これがないと直列復元化したときにsingletonなのにコピーが発生しちゃう。

@see java.io.Serializable

本では挙げられていなかったが、マルチスレッド環境下でもsingletonが複数存在する問題がある。(参考:http://www.atmarkit.co.jp/fjava/javatips/075java007.html)

--------------
3.utilクラス
java.lang.Mathのようなpublic staticだらけのクラスのコンストラクタはprivateにしてnew不能にする。

--------------
4.オブジェクトの再利用
-immutableなオブジェクトは再利用できる。
良くない例としてnew String("hoge");が挙げられている。これは"hoge"という不変クラスのコピーを作るので
javadocに書いてあるように使っちゃイカンという話。

-不変クラスにコンストラクタとstatic factory methodの両方が用意されてる場合はstatic factory methodの方が工夫されてたりするのでそっち選んだ方がイイ。
(この辺は1.と絡むなぁ...。)
本当かと思ってIntegerのvalueOf(int i)のソースを見てみた。

public static Integer valueOf(int i) {
	final int offset = 128;
	if (i >= -128 && i <= 127) { // must cache
		return IntegerCache.cache[i + offset];
	}
	return new Integer(i);
}
 -128 ~ 127はキャッシュ使ってた!しらんかった!

-よく呼ぶmethod内でのnewは避ける!
isXXX()内で判定基準として使われるオブジェクトは使い回せ。

-ちょっと脇道にそれてLazy Initializationに関する話が少々。

-可変だけど再利用できる例
"ある特定のオブジェクトに対する" GoFアダプターパターンのアダプターに当たるクラス。
(この辺分かりづらかった。要するにアダプターは内部に保持してる移譲先オブジェクト,アダプティーの代替インターフェースを提供してるだけなので、使う側からしたら1コのアダプターさえあれば十分だよねという話。)

-再利用の執着に注意
オブジェクトの再利用によるペナルティ(bug,security hole) >> 不要なコピーによるペナルティ(メモリの無駄喰い)
これは頭に入れておこうとおもた。

--------------
5.メモリリーク
起こしやすい例
-クラスが独自のobject poolを保有してるとき。→使わなくなった参照にはnullを。
-キャッシュ機構を自分で実装したとき。→WeakHashMapを使え。

注意しなきゃイカンのは「やべ、今までnullなんて突っ込んだこと無かった!」と思ってはいけないことだろう。参照にnullをあえて設定するのは上記ぐらいのもんで、通常よく使うローカル変数とかはスタックフレームを抜ければまず間違いなく解放される。

WeakHashMapなんてクラス、初めて知ったよ。参照の種類やReferenceクラスに関しては過去にブックマークしたEwigkeitさんのこの記事が詳しい。
実装の仕方はjavadocに載ってる。

実装上の注意: WeakHashMap 内の値オブジェクトは、通常の強参照によって保持されます。このため、値のオブジェクトが直接的にも間接的にも強くそれ自体のキーを参照しないようにしてください。そうすれば、キーが破棄されないようになります。値のオブジェクトが WeakHashMap 自体を介してそのキーを間接的に参照するようにしてください。つまり、値のオブジェクトはほかのキーオブジェクトを必ず参照し、その関連付けられている値のオブジェクトが今度は最初の値のオブジェクトのキーを必ず参照します。この問題に対応する 1 つの方法は、値自体を m.put(key, new WeakReference(value)) のように、挿入前に WeakReferences にラップし、次に各 get でラップ解除することです。

取り出すときはこんな感じだろう。
a.)WeakReference wRef =m.get(key);
b.)wRefのnullチェック
c.)wRef.get();

ただし、この方法はGC依存なのでいつ消えるかわからんなんてヤダ!って人のためにEffective Javaでは代替案も示してくれている。LinkedHashMapを継承する方法だ。使い方としてはremoveEldestEntryメソッドのドキュメントを見ればよいのだが、イマイチ分かりづらかった。自分はremoveEldestEntry()とコレを使用しているaddEntry()のソースを見た方が分かり易かった。

試しに組んでみた。

追加時に一番古いもんから消えて行くからWeakHashMapよりは動きが予想できる。

--------------
6.finalizerの話
Object.finalize()を継承する方法は×。
GC依存なのでいつ実行されるのか、そもそも実行されるのかどうかも分からない。
→Stream系クラスに見られるようなclose()とかを用意しておき、利用者がfinally句でこれを呼び出すようにするのが正解。

Object.finalize()の存在意義は?
 -close等が呼ばれなかったときの保険
 -(いつ回収しても良いような)あまり重要でないネイティブリソースを持つオブジェクトならok

finalize実装時の注意点
 -finalize()をきちんと実装したあるクラスの子クラスを作るときは子のfinalize()内でfinally句併用でsuper.finalize()を呼ぶ。P22にコード例あり。

この注意点を無視した子クラスから親を守る方法としてfinalizer guardianというパターン手法の説明を後半でしている。P23にコード例あり。

あるクラスHoge内に匿名クラスを作り、この中でHogeの後始末を行うfinalize()を実装し、この匿名クラスのオブジェクトを一個だけHogeのインスタンスフィールドhogeFinalizerGuardianとして持たせてやる。そうしてやるとHogeと匿名クラスのインスタンスが1対1の関係になるので、仮にHogeのインスタンスがGC対象となったらhogeFinalizerGuardianも一緒にGC対象となるってわけ。もし子クラスを定義されちゃっても必ずhogeFinalizerGuardianもくっついてくるので、子は親のfinalizerを呼ばなくて済む。

コレ考えたヤツは頭いいなぁと思った。

#一応2章はココまで。3章に進みます

今までの生活ぶりを考えると4日連続6時起きって奇跡だよなぁと思ってしまう。

平日あまり寝られなかったので、今日は思いっきり昼まで寝るつもりだった。
しかし、悲しいかな体が早起きに慣れてしまい、8時間以上はぶっ通しで寝れなくなってしまった。

丸一日自由に使えるので、とりあえずやりたいことをやった。
-髪ばっさり切った。これで寝癖で髪の毛か朝からぐちゃぐちゃなんてこともしばらくはなさそう。
-Binary Hacks、やっと読了。BSD Hacksの時よりも知らないこと満載の楽しい本だった。一回読んだだけでは全てを吸収しきれなかったので、また何回か読み返したい。
次はちょっと読んでしばらく放置状態だったEffective Javaにすっかな。Perl Hacksは引き続き、並行して読む(現在40%)。
どうも最近LDRのfeed消化に費やす時間の方が多くてイカン。タイムリーなネタで勉強できるのはイイのだが、昔と比べると明らかに本を読む時間が減ってる。少なくともこれからは一日一節ぐらいのペースを保っていきたい。

駅でえらい並んでしまった。
なんだかんだで1時間近く浪費してしまってもったいない。

--
#研修で模試を受けたけど、DVDという単語を聞くと、もうあの漫画しか頭に思い浮かばないんです。設計どころじゃありません。困ったもんです。

4/14追記
以下の内容はReblogCommnad@7308に対するパッチであり、12日のTumblrの仕様変更により、闇に葬られました。

微妙に新しくなったtumblrでReblogCommandを動くようにするためのパッチ « ZeroMemoryを参考にして暇な時間を見つけてまた同等品を作るかもしんない。→作った → 更にtombloo依存解消版作った

------------

以前紹介したようにTumblrでreblogする際に自分はReblogCommandというグリモンスクリプトを使っていたのですが、privateモードでも気軽にポチポチしたいなと思い、ちょっと格闘したらできたので載せておきます。(reblogcommand_with_privatemode.user.js.patch)

tのお隣のyキーでprivate reblogになります。

お約束ですが本パッチ適用は自己責任でお願いします。いつものごとく、べーたくおりてぃーです。

ああ、けどこんなもん作ってる場合じゃねぇ。基本情報の復習しないと...。
明日恥ずかしい点数を取ったら生暖かい目で見てくれるといいなぁ。

→はてなダイヤリーなどで外部プレーヤーのお世話になる。(やり方の紹介:記事本文にニコニコ動画が貼り付けられるようになり、動画ページにも掲載されるようになりました - はてなダイアリー日記)


以前、twitterを始めてみたときにはてなのアカウントを取得したので、せっかくだからニコニコ部に入部。

早速使ってみた。
Lyoのニコニコ動画のリンクを貼るだけの簡単な日記 : エキプロ + HELLSING
気になった動画があったら、こっち使っていきます。

満員電車のおかげでやたらクタクタ。あとスーツや革靴にやっぱり慣れていないと言うのもあるか...。

まぁ、今までのバイトだと単純に時間がお金に替わっていただけだったのだけれども、今度からは責任というものが一緒にくっついてくるのだなぁとしみじみ思った。

明日も遅刻するわけにはいかないので、今日も早めに寝よう...。

このアーカイブについて

このページには、2008年4月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2008年3月です。

次のアーカイブは2008年5月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

OpenID対応しています OpenIDについて
Powered by Movable Type 7.9.3