【Java】泛型
泛型(Generics)是指
-
- 任意の型を受け付けるクラス・メソッドに対して特定の型を割り当てて、型専用のクラスを生成する機能
これでメンバー要素の型をコンパイル時に保証できる
ジェネリック型を定義する
class クラス名<型パラメータ,…>{クラス}
ex:型パラメータEを宣言 public class ArrayList extends AbstractList{
型パラメータ:特定の型を受け取るための宣言<…>の部分
インタンスにに任意型を割り当てる
T(Type)・E(Element)・K(Key)、V(Value)
型変数:型パラメータ内で宣言された型のこと
インスタンスメンバーの引数/戻り値
ローカル変数の型
ネストした型
ジェネリクスではインスタンス化の際に、ArrayListが生成される。クラスメンバーの型としては使えない
イレイジャ(Erasure):このように実行時に不要な型情報をコンパイル時にObject型に変換すること
実型パラメータ(型引数):ジェネリック型をインスタンス化する際に指定する具体的な型のこと(Integerなど)
new ArrayList****:
パラメータ化された型:型引数で特定の型が割り当てられたジェネリック型のこと(ArrayListなど)
new **ArrayList**:
类型参数的约束
メソッドがある引数をもつ前提にしたい
下記の例では、T型の変数x,yが必ずcompareToメソッドを持つとは限らないのでエラーになる
compareToメソッドを持つ=Comparableインターフェースを実装するString,Integer,Fileなどのクラス
//エラー
public class GenericConstraint <T> {
public int Hoge(T x, T y) {
return x.compareTo(y);
}
}
-
- →型パラメータで制約(境界型)を付与
<型パラメータ extends 境界型, ..>
ingBuilder境界型を指定された型パラメータは、コンパイル時にObject型ではなく境界型に変換される
以下のようにComparableインターフェースを実装したString型などはGenericConstraintクラスに渡せる
//compareToメソッドを認識できる例
public class GenericConstraint <T extends Comparable<T>> {
public int Hoge(T x, T y) {
return x.compareTo(y);
}し
}
-
- 境界型はクラス/インターフェース指定可能
implementsでなくextends
インターフェースは複数指定可能
クラスは1つのみ(もしくは0)
クラス→インターフェースの順で記述
public class MyGeneric {
泛型方法构造函数 hé
-
- 引数/戻り値・ローカル変数などの型を呼び出し時に決められるメソッド、コンストラクタのこと
ジェネリックメソッドはジェネリック型とは独立なので非ジェネリック型でも定義可能
[修飾子]<型パラメータ>戻り値型 メソッド名(引数の型 引数名, ...)
[throw句]{
メソッド本体
}
境界的野牌类型
共変(covariant):配列では派生クラスを基底クラスに代入できるParent/Childに継承関係がある場合Child[]はParent[]に代入できる
Object[] data = new String[5];
Object/String には継承関係があるのでObject型入れるにString配列は代入可能
data[1] = 10;のdataの実態はString[]なのでArrayStoreException
不変(invariant):ジェネリクスのコレクション
Parent/Childに継承関係があってもArrayListはArrayListに代入できない
ArrayList
//NG例
import java.util.List;
public class GenericBounded {
//List<Parent>型のリストを受け取り出力
public void show(List<Parent> list) {
for (var p : list) {
System.out.println(p.getName());
}
}
}
import java.util.ArrayList;
import java.util.Arrays;
public class GenericBoundedBasic {
public static void main(String[] args) {
var cli = new GenericBounded();
var data1 = new ArrayList<Parent>(Arrays.asList(
new Parent("かえる"), new Parent("にわとり"), new Parent("とんぼ")));
var data2 = new ArrayList<Child>(Arrays.asList(
new Child("おたまじゃくし"), new Child("ひよこ"), new Child("やご")));
cli.show(data1); //OK
//List<Parent>型の引数にList<Child>型の値は渡せない
cli.show(data2); //コンパイルエラー
}
}
- showはリストの中身を参照するメソッドなので値の代入は発生しない→境界ワイルドカードでParent型、またはその派生型を認める(共変)List型の引数にList型を渡せるようになる要素の追加、更新はできない境界ワイルドカード型では境界型で値を参照できることのみ
import java.util.List;
public class GenericBounded {
//境界ワイルドカード
public void show(List<? extends Parent> list) {
for (var p : list) {
System.out.println(p.getName());
}
}
}
标准库的一个例子
public boolean addAll(Collection<? extends E> c){
Object[] a = c.toArray();
//略
}
- addAll(Collection
下限境界的野卡类型
- 上限境界ワイルドカード:指定境界型を上限、その下位型も認める(<? extends E>)下限境界ワイルドカード:枷型に対して基底型を渡せる=反変(<? super T>)addAllメソッドでは、下限境界ワイルドカード型Collection<? super T> で、型Tもしくはその上位型を要素に持つコレクションを渡せるaddAllに下限境界ワイルドカード型がなかったらString型要素の追加にはArrayList
public static <T> boolean addAll(Collection<? super T> c, T... elements) {
boolean result = false;
for (T element : elements)
result |= c.add(element);
return result;
}
//ArrayList<Object>に対してString型の要素の追加を許容
import java.util.ArrayList;
import java.util.Collections;
public class LowerBoundedBasic {
public static void main(String[] args) {
var list = new ArrayList<Object>();
Collections.addAll(list, "neko", "inu", "tori");
System.out.println(list); //[neko, inu, tori]
}
}
非境界野牌类型
- 境界型を持たないList<?>ように指定注意:型安全を保証するためにはTを引数として受け取るメソッドを呼び出せないメソッドの戻り値となるTは全部object型
import java.util.List;
public class UnBounded {
public static void showList(List<?> list) {
for (var item : list) {
System.out.println(item);
}
//list.add("Hoge");//型が決まってないので値の引き渡し不可
//list.add(null); //例外的にnullはOK
// Object obj = list.get(0); //取得した結果はString型ではなくObject型!!
}
}