ジェネリクス
ジェネリクスは型をパラメータ化することができる仕組みで、Java11どころかJava5からあります。
使わないとListとかMapとかを使えないに等しいような状態になるので、まったく知らないという人もいないと思いますが、自分で型パラメータの宣言をしたことはなかったり、extendsやsuperが出てくると自信がなくなったりする人は少なくないのではないでしょうか。
自分で宣言して利用しようとしたときに、まず悩むのはどこに書いたらいいのかです。以下の3パターンあります。
- クラスに宣言する
- メソッドに宣言する
- コンストラクタに宣言する
個人的にコンストラクタに宣言したくなったことは一度もないのですが、できるかどうかでいうとできます。
クラスやコンストラクタに宣言する場合の例は以下です。
public class GenericsClass <T, A extends Piyo> {
T obj;
A piyo;
Huga huga;
public <B extends Huga> GenericsClass(B b) {
this.huga = b;
}
public void setT(T obj) {
this.obj = obj;
}
public T getT() {
return obj;
}
public void setPiyo(A piyo) {
this.piyo = piyo;
}
public A getPiyo() {
return piyo;
}
}
メソッドに宣言する場合の例は以下です。
public class GenericsMethod {
public static <T> void inputT(T obj) {
System.out.println(obj + ":T");
}
public static <T extends Piyo> void inputT(T obj) {
System.out.println(obj + ":T extends Piyo");
}
public static <T> T returnT(T obj) {
return obj;
}
public static <T> void copy(List<? extends T> from, List<? super T> to) {
for (int i = 0; i < from.size(); i++) {
to.add(from.get(i));
}
}
}
知らないと混乱する、主な注意点は以下です。
-
T extends Number
は「TはNumber型もしくはそのサブクラス」という意味 -
? extends T
は「T型もしくはそのサブクラス」という意味 -
? super T
は「T型もしくはそのスーパークラス」という意味 -
new T()
とかnew T[]
とかはできない - コンパイル時に型情報は消去される。そのままObject型扱うになるか、
<T extends Number>
みたいになっていた場合はNumber型扱いになる - 素の状態だと共変性がない。
List<Number> list = new ArrayList<Integer>();
とかはできない。List<? extends Number> list = new ArrayList<Integer>();
とすればOK
いつ使うのかよく分からないのは? super T
じゃないでしょうか。
これはたとえば以下のような場面で使います。
public static <T> void copy(List<? extends T> from, List<? super T> to) {
for (int i = 0; i < from.size(); i++) {
to.add(from.get(i));
}
}
こうしておくと、以下はエラーになりません。
GenericsMethod.copy(Arrays.asList(1 , 2, 3, 4, 5), new ArrayList<Number>());
ダイアモンド演算子
ダイアモンド演算子の追加で二回書かなくても推論してくれるようになりました。
List<Number> list = new ArrayList<>();
このダイアモンド演算子は型推論と相性が悪いというか両立しないようなところがあります。
// 以下は書けるけれどvar list = new ArrayList<Object>();と同じ意味になってしまう
var list = new ArrayList<>();
多くの場合は結局、以下のように書く必要があります。
var list = new ArrayList<Number>();
シリーズJava再入門
いまからJava8にしよう!だってJava11よりサポート長いし!という判断もあると思いますが、11に引っ越そうとしている方や、11の次のLTSになることを予定されている17への移行を目指している方向けのJava再入門です。
- Java7以降の歴史 機能追加とサポート期間
- モジュールシステムとクラスパス、Gradle
- Java再入門 JVMオプション
- Java再入門 ~Java11 ジェネリクス、ダイアモンド演算子
- Java再入門 ~Java11 日付時刻API
- ~Java11 リソース付きtry文
- ~Java11 ラムダ式、メソッド参照、Stream、Optional、ローカル変数型推論
- ~Java11 ExecutorService/Future、Fork/Join
- 今後:テキストブロック
- 今後:switch式、パターンマッチングinstanceof
- 今後:record