5.26-5.29汎用型の使用

3407 ワード

次のクラスでは、汎用型を使用します.
public class Container <E>{
	private List<E> elements=new ArrayList<E>();
	
	public void addAll(List<E> list){
		elements.addAll(list);
	}
	
	public void removeAll(List<E> list){
		list.addAll(elements);
		elements.clear();
	}
	
	public static <T> List<T> union(List<? extends T> list1,List<? extends T> list2){
		return null;
	}
}

 
次のテストコードを使用してエラーを報告します.
		List<Integer> list1=Arrays.asList(1,2,3);
		
		Container<Number> container=new Container<Number>();
		container.addAll(list1);//     

 
以上のテストコードは、Container宣言を使用しているため、addAll()はListタイプのパラメータ値のみを受け入れます.したがって、IntegerはNumberのサブクラスであるにもかかわらず、1つのListタイプのパラメータが入力されるとエラーが表示されます.
 
汎用ワイルドカードを使用して汎用メソッドの適応性を高めることができます.基本原則はPECS(producer-extends,consumer-super)です.前述の例では、addAll()から入力されたlistパラメータはcontainerオブジェクトにデータを提供するので、このlistオブジェクトはcontainerに対してproducerです.同様に、removeAll()が入力したlistパラメータはcontainerを使用して削除されたオブジェクトであるため、このlistはconsumerです.以上の原則に基づいて、修正方法は以下の通りである.
	public void addAll(List<? extends E> list){
		elements.addAll(list);
	}
	
	public void removeAll(List<? super E> list){
		list.addAll(elements);
		elements.clear();
	}

 
すべてのComparable、ComparatorはConsumerです.このインタフェースを使用する場合は、次の宣言を使用します.
	public <T extends Comparable<? super T>> T max(List<T> list){
		return null;
	} 

 
以下のテストunion()のコードはエラーを報告し、入力されたパラメータはそれぞれList、Listタイプであり、コンパイラはどのパラメータタイプを使用すべきか分からない(なぜコンパイラは結果を返すタイプListから実際のパラメータタイプを取得しないのか?)
		List<Integer> list1=Arrays.asList(1,2,3);
		List<Double> list2=Arrays.asList(4.0d,5.0d,6.0d);
		
		List<Number> list=Container.union(list1, list2);//     

 
コンパイラが使用する実際のパラメータタイプをNumberとして明示的に指定するには、次のように変更します.
List<Number> list=Container.<Number>union(list1, list2);

 
 汎用型を使用すると、「コンテナ」が格納できる要素のタイプを制限できます.例えば、Listの制限コンテナListには、タイプEの要素しか格納できません.Mapタイプのコンテナと同様に、次のインタフェースキーのタイプがClassであり、valueがT、すなわちvalue.classタイプがkeyと同じであることをtypesafe heterogeneous containerと呼ぶ.
注意:Class.asSubclass()を呼び出してタイプ変換できます.
public class Favorites {
	public <T> void putFavorite(Class<T> type, T instance);

	public <T> T getFavorite(Class<T> type);
}

 
実装クラス:
public class Favorites {
	private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();

	public <T> void putFavorite(Class<T> type, T instance) {
		if (type == null)
			throw new NullPointerException("Type is null");
		favorites.put(type, type.cast(instance));//     type       
	}

	public <T> T getFavorite(Class<T> type) {
		return type.cast(favorites.get(type));
	}
}