読書会(Effective Javaプログラミング言語ガイド)第2回議事録
[ 戻る ]
Effective Java 第 2 回議事録
2002年 6月22日 10:00-17:00 @目黒勤労福祉会館4F和室
参加者(敬称略)
佐藤慶治 村山敏清 荒井彩子 中村圭輔 門脇太郎 吉関 コセキ
天野
高橋(徹) 高橋(智) 福嶋航 山本貴士 伊藤哲 根本和郎(記)
鈴木 石黒
柴田芳樹(翻訳者)
p38 Hash code より再開
○ volatileについて
private volatile int hashCode =0;
について intはアトミック処理をするが、読み出しの場合はvolatile必須。
longやdoubleはアトミックではない。
○ hashmapに長いstringは入れるな
ハッシュテーブルの構造は事前に、理解していること、hashそのものの説明はな
い。
hashcodeの計算は最初の数文字だけを見るのでhashが1個所に集中することがあ
る。
(これは、JDK1.xの頃のString#hashCode()の実装がそうだったという話)
stringのhashmapはキャッシュするだけで早くなるかもしれない(テスト必要)。
---------------福嶋さんテスト報告より----------------------
J2SE v1.4 ではキャッシュしているかもしれない、という話でした
手元のMac OS Xに入っている
Java(TM) 2 Runtime Environment, Standard Edition (build
1.3.1-root-020219-20:07)
Java HotSpot(TM) Client VM (build 1.3.1, mixed mode)
で見てみたところ、ちゃんとキャッシュしていました。
/** Cache the hash code for the string */
private int hash = 0;
:
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++)
h = 31*h + val[off++];
hash = h;
}
return h;
}
---------------ここまで福嶋さんテスト報告----------------------
stringのget/putは指定キーの設定が大変
長いstringの比較をすると、大変時間が掛かるはず、optimize itを買ってでパ
フォーマンスを比較しましょう
toStringにMD5を使ってみるのはどうか、ユニークさを保って速く処理できそう。
詳しくはsrc.jarを見ましょう
日本語として記述が不明瞭な点 「 向き合うことになるかもしれません」--> 「問
題となります。」
1文字おきの16文字までの比較がstringのhashmapの算出だがローマ字の比較におい
て母音があたると不利。
defaultのhashcodeの実装形態はべき乗を使っており、遅そう
なおoverflowに関しては下側32bitは切り捨て処理をしつづけるので一箇所に固
まることはない。
○ Thread[main. 5,main]の意味
Thread[名前,ブライオリティ,グループ] これを知っている人は何人? 説明がな
いのでキビシイ。
○ toStringのフォーマット変更は途中からは不可能
XMLに埋め込むときに string --> ここのデータにする
toStringではなくマーシャルするべき、 accessorで取り出せないものは解析す
べきではない。
log出力のparseが主たる用途か、ならJava1.4のlog機能を使うべきか。
あとはlog4jをしっかり勉強して考えましょう。
java.util.text のformatterは書式指定が使いにくい、右詰はなかったハズ
項目10 clone
○ getlass()の一致はObjectクラス
super.clone()はjava.lang.Objectに到達するまで上に上がりつづける。
Java.lang.Object()の実装は shallow copy
transientフィールドはcloneでcopyされるか実験必要
再帰呼び出しは実際はreturnの中で呼んでいる。
hashtableの複製とは新しいテーブルにコピーすること。
super.clone()でhashtableを新規に作る。
同じ手順で複製する。
全く同じモノを同じように作る。
ここで、内部のHashtable.Entryを複製するのではなく、旧インスタンスの
内容をgetで取り出し、新インスタンスにputで追加していく、というものでした。
パフォーマンスを考えるととget/putの方が遅そう。
deepcopyのclone() とは constructor()と同じ、じゃ複製ではなくて生成ではな
いか。
clone()メソッドにかかわらずコンストラクター デシリアライズは危険メソッド
として注意がいる。
極論すれば生成に関与するメソッドは全て注意すること。
インスタンス生成中にインスタンスメソッドを呼ぶのは避けた方が良い、という話
copyConstructor()を利用したほうが良い。
p50 訳注
clonable()は、method objectを生成してinvokeする reflectionならにげられる
が
実際にはそのままでは複製できない、 基本的には自分で作らなければ、使うこ
とはできない。
ArrayCopy と配列のcopy は何が違う
Objet[].x={A,B,C}とは Object[]y=x.clone(); でいいのではないか。
ArrayCopyは長さの一致しない配列の複製に使用可能(確認必要)
○ comparebleの実装
第4章 クラスとインターフェイス
JLS6.6.2の示す例外
親クラスのprotectedは見えるが、派生した自分以外の子クラスのインスタン
スには見に行けない。
(親は見えるが兄弟は、別物)
項目13 不変性を選ぶ
getxxx()のgetは省略してもいいこととすることもできる、isXXXX()はあんまり
考えない。
bean仕様準拠のできそこない見たいに考えてよいのかも。
○ memorymodelの考え方
複数スレッドに対してどのようにメモリが見えるかどうか。
別Threadが同一オブシェクトに対してどのようにアクセスするかどうか。
volatileの意味
=Cは最適化指示
=Javaではdoubleとlongのアクセスのアトミック性を保証すること。
Synchronizeなしでも最新のデータを保証する。
mutator=可変行為をするメソッド=setter() (mutant=突然変異)
不変クラスのfinalizeの仕方は classをfinalにするか各methodをfinalにする
かのどちらかである。
Template method(GoF)の考え方とは異なり、不変クラスの考え方である。
p67
ソース中resultローカル変数の存在意義はread once write onceの実現の為
そうでないと訳注の様に、2回読み込みが発生して、値が変わるおそれがある。
参考(double-locked checkイディオム)
ちなみに String#hashCode()を見てみると、一旦ローカル変数に値をとってい
る。
コーディングスタイルとして注意の喚起が必要。
コンストラクターの中でThreadをスタートするような人がいるが
まだオブジェクト生成が完了しないうちに走らせると危険。
start()すると優先的にthreadが回りだすことがある。
yield()をJVMが必ずしも正しく処理する可能性はない、気休めにしかならない。
次回はp69 項目14 継承よりコンポジション より。
以上
[ 戻る ]