SJC-P ジェネリックス 型パラメータ
ナビゲーションに移動
検索に移動
目次
SJC-P ジェネリックス 型パラメータ
型パラメータ(クラス)
以下のような箇所で使用できる
- クラスの型
- インスタンス変数の型
- 配列の型
- コレクション等、他の型パラメータに渡す
- メソッド引数
- メソッド戻値
- キャスト
通常
import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Date; import java.util.List; public class GenericsTest4 { public static void main(String[] args) { GenericsTest4 me = new GenericsTest4(); GenTypeTest<Date> gd = me.new GenTypeTest<Date>(); for (int i=0; i<5; i++) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Date d = new Date(); gd.addMember(d); } Date[] da = gd.getMemberAry(); for (Date d : da) { System.out.println(d.toString()); } } private class GenTypeTest<T> { // クラスの型 private T member; // インスタンス変数の型 private T[] members; // 配列の型 private List<T> memList // コレクションに渡す = new ArrayList<T>(); private void addMember(T member) { // 引数 memList.add(member); } private T[] getMemberAry() { // 戻値 // members = new T[memList.size()]; // NG インスタンスの生成 member = memList.get(0); members = (T[])Array.newInstance( // キャスト member.getClass(), memList.size()); memList.toArray(members); return members; } } }
継承関係を指定
- <T extends [Class or Interface]> で、指定クラス(インターフェース)の派生クラスであることを指定
- Clazz<? super [Class or Interface]> で、Clazzが、指定クラス(インターフェース)の基底クラスであることを指定
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class GenericsTest5 { public static void main(String[] args) { GenericsTest5 me = new GenericsTest5(); CompareUtil<Double> dc = me.new CompareUtil<Double>(); dc.addNum(1.23); dc.addNum(2.34); dc.addNum(100.00); dc.addNum(-5.23); System.out.println(dc.getMax()); } // T型の基底クラス(T型を含む)に適応する Comparable を継承した T型 private class CompareUtil<T extends Comparable<? super T>> { List<T> numList = new ArrayList<T>(); public void addNum(T num) { numList.add(num); } public T getMax() { Collections.sort(numList); return numList.get(numList.size()-1); } } }
メソッドでジェネリックス型を利用する
- 戻値より前に書く必要がある
- ?は使えない(よく考えればわかる)
public class GenericsTest6 { public static void main(String[] args) { System.out.println(MathUtil.log10(365)); System.out.println(MathUtil.log10(0.56789)); // ボクシングと絡めて利用すると、挙動がややこしい // 上の例 MathUtil.log10(365) はOKだが、ここで同様にすると、エラー // オートボクシングにより、365 → Integer になり、戻値も Integer // アンボクシングにより、Integer → int で、Math.pow(double, double)に適合しなくなる // (Doubleにアンボクシングできない:java.lang.ClassCastException: java.lang.Double) System.out.println(Math.pow(10,MathUtil.log10(365.0))); System.out.println(Math.pow(10,MathUtil.log10(0.56789))); } } class MathUtil { // メソッドで、ジェネリクス型を使う // いろいろバージョンをオーバーロードしなくてもよい public static <T extends Number> T log10(T num) { double ret = Math.log10(num.doubleValue()); return (T) new Double(ret); } }
拡張forループで使用する
Messageクラスを保持するMessagesクラスを拡張forループに対応させる
- Iterable<Message>の実装
public class Messages implements Iterable<Message> { private List<Message> messages; private List<Message> getMessages(){ if (this.messages == null) { this.messages = new ArrayList<Message>(); } return this.messages; } public Iterator<Message> iterator() { return getMessages().iterator(); } public void add(int index, Message msg) { getMessages().add(index, msg); } public Message get(int index) { return getMessages().get(index); } }
© 2006 矢木浩人