翻訳が、「ジェネリクス」ではなく、「ジェネリックス」なので、表記を合わせています。
p.n表記は、EffectiveJavaのページ番号です。
前史(ジェネリックス以前)
コレクションから読みだしたすべてのオブジェクトをキャストしていた。(挿入する型を間違えるとキャスト失敗)
現在(ジェネリックス時代)
個々のコレクションに許される型をコンパイラに伝え、コンパイラは自動的にキャストを挿入。誤った型を挿入しようとすると、コンパイル時に判明。
ジェネリックスを理解するために。変性の話。
(この辺参考URLから)
変位 | 意味 | Javaでの例 |
共変 | 広い型から狭い型へ | A<P>はA<C>のスーパータイプ |
反変 | 狭い型から広い型へ | A<P>はA<C>のサブタイプ |
非変 | 型を変換できないこと | A<P>とA<C>の型に関係はない |
Javaではすべてのジェネリック型は非変(ジェネリック型変数の変位指定はできない)。
不変であるということは、List<Object>のパラメータに、List<String>を渡すことができない。
No. 23 新たなコードで原型を使用しない
Javaのジェネリック対応は、過去バージョンとの互換性の維持が前提となっているため、犠牲にしている部分がある。
- 原型(Raw Type)が使用できること
- 変位指定ができない
要素型が不明な場合、原型を使用すると下記のように書いてしまうのはよくない(p.110)
[java]
static int numElementsInCommon(Set s1, Set s2) {
int result = 0;
for (Object o1 : s1)
if (s2.contains(o1))
result++;
return result;
}
[/java]
非境界ワイルドカード型で書きなおすと(p.111)
[java]
static int numElementsInCommon(Set s1, Set s2) {
int result = 0;
for (Object o1 : s1)
if (s2.contains(o1))
result++;
return result;
}
[/java]
- 非境界とは?
- 上限や下限がないこと。
原型を使用しない、の例外2つ
クラスリテラルでは原型を使用しないといけない(非境界ワイルドカード型だったらOK)
instanceofつかうとき
[java]
if ( o instanceof Set ) {
Set m = (Set) o; //Setでキャストする必要がある
}
[/java]
No. 24 無検査警告を取り除く
省略
No. 25 配列よりリストを選ぶ
なぜ配列よりリストを選ぶべきなのか?
配列は実行時の型安全は提供するが、コンパイル時の型安全は提供しない
- 配列の特徴
- 共変である
- 具象化されている
配列よりリストを選ぶ例(p.119)
[java]
import java.net.InterfaceAddress;
import java.util.ArrayList;
import java.util.List;
public class sample01 {
//元のコード
static
E[] snapshot = (E[]) list.toArray(); //警告
E result = initVal;
for(E e : snapshot)
result = f.apply(result, e);
return result;
}
//安全にする
static
List
synchronized(list) {
snapshot = new ArrayList
}
E result = initVal;
for (E e : snapshot)
result = f.apply(result, e);
return result;
}
interface Function
T apply (T arg1, T arg2);
}
}
[/java]
以下次回に持ち越し
0 件のコメント:
コメントを投稿