ねっとぱんだ-プログラミング勉強ブログ-

Webデザイン、プログラミングの勉強ブログ。

【java】generics型 (総称型) ※追記

generics型 (総称型)

参考
http://d.hatena.ne.jp/Nagise/20101105/1288938415
http://qiita.com/MuriNishimori/items/31d07fd49eec579f3ba1
  • Java SE5.0 から導入
  • 型を変数化して汎用化(多目的に何にでも使えるように)したデータ型でクラスやインターフェースを作れる。

クラスをスコープ(有効範囲)にした場合での型変数

  • クラス名の後ろの<>(angleBrackets)内に型変数を記述。
  • newする時のクラス名の後ろの<>で型変数へ型をバインドする。
//データ型をTで表現(型変数という)
//良くタイプという意味でTが使われる。
class MyData<T>{
	
	public void getParam(T x){
		System.out.println(x);
	}
	
}

public class practice{
	
    public static void main (String[] args){
    	
        //データ型を<>で指定
    	//参照型しか使えない
    	MyData<Integer> i = new MyData();
    	i.getParam(2);
        
    	MyData<String> s = new MyData();
    	s.getParam("hoge");
    }
    
}

メソッドをスコープ(有効範囲)にした場合の型変数

  • 戻り値宣言の前に型変数を宣言
  • インスタンスメソッドなら
    オブジェクト.<型>メソッド名s()
    と書く
  • staticメソッドなら
    クラス名.<型>メソッド名
    と書く
  • thisを使う場合
    this.<型>メソッド名()
    と書く
public class Practice {
	
    //<T2>で型変数を記述
    //次に変数を使いメソッドの型を宣言
    //引数でも型変数で型を宣言している
	public <T2> T2 hoge(T2 palam){
		return palam;
	}

	public static void main(String arg[]){
    
		Practice p = new Practice();
        
		System.out.println(
            //型変数に型を宣言
			p.<String>hoge("hoge")
		);

	}
	
}

型を書くときの慣例

参考:shttp://java.keicode.com/lang/generics-naming.php

  • 通常の変数と区別するために大文字一文字を使う
  • E 要素 (Java コレクションフレームワークで広く用いられている)
  • K キー
  • N 数値
  • T 型
  • V 値
  • S, U, V... 二番目、三番目の型

メリット

  • 型を間違えた時にコンパイル時にエラーになるので間違えない
  • キャストの手間が省ける

C++のテンプレート(template)と見た目がそっくりな機能らしい。

generitics型の用語

記述した時のそれぞれの部位の名称などです。

境界というのは、型情報がどこまでのオブジェクトを含めるのかの設定(?)

参考
http://qiita.com/pebblip/items/1206f866980f2ff91e77
https://www.amazon.co.jp/Effective-Java-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9E%E3%82%AC%E3%82%A4%E3%83%89-Joshua-Bloch/dp/4894714361

ジェネリック型 generictype List <E>
仮型パラメータ type paramater List <E>
パラメータ化された型 paramaterized type List <String>
実型パラメータ actual type parameter String
原型 raw type List
境界型パラメータ bounded type parameter <E extends Number>
非境界ワイルドカード型 bounded type parameter List<?>
境界ワイルドカード型 bounded wildcard type List <? extends Number>

変性

型Bが型Aのサブタイプであるとき、
ジェネリクス型X<T>において

  • X<B>が X<A> のサブタイプであれば
    共変(covariant)
  • X<A> が X<B> のサブタイプであれば
    反変(contravariant)
  • どちらも成り立たない場合
    非変(invariant)

例えば Numberクラス は 数値に関係するクラス(AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short
)のスーパークラスで、Integerクラスはそのサブクラスです。

この時

  • List が Listのサブタイプなら共変。
  • List が Listのサブタイプなら反変。
  • List と Listに継承の関係がないなら非変。

Javaジェネリクスは非変

class List<T>{
	
	private T x;
	
	public List(T x){
		this.x = x;
	}
	public T getT(){
		return this.x;
	}
}

public class practice {

	public static void main(String arg[]){
        //Integer型
		List<Integer> intList = new List<Integer>(123);
        //Number型
		List<Number> numList = new List<Number>(123);
		List<Number> numList2 = new List<Number>(123);
	   
        //Number型にNumber型を入れる
		numList = numList2; //OK
        
        //Number型にInteger型を入れる
		numList = intList; //コンパイルエラー       

	}
	
}

? ワイルドカード

  • ?の部分はどの型でも入る。
  • extendsを使い型を継承するとその型以上の階層の型を制限できる。
  • superを使い型を継承するとその型以下の階層の型を制限できる。
  • List からgetした要素はObject
    ?はどの要素でも入る為最も汎用的なObjectクラスになる
//ワイルドカードを使い、クラスの上限境界をNumberオブジェクトに設定することもできる
//(例)class List<T extends Number>
class List<T>{
	
	private T x;
	
	public List(T x){
		this.x = x;
	}
	public T getT(){
		return this.x;
	}
}

public class practice {

	public static void main(String arg[]){
		
		//通常の型指定
		List<Number> numList = new List<Number>(123);
		//ワイルドカードを使い、インスタンスの上限境界をNumberオブジェクトに設定
		List<? extends Number> intList = new List<Integer>(123);
		//ワイルドカードなので、クラスに境界がなければどの型でも入る
		List<?> strList = new List<String>("a");
		
		//上限境界がNumber、下限境界がワイルドカードなので、Number以下の階層の
		//型がなら何でも代入可能。
		intList = numList;
		//ワイルドカードの型情報のインスタンスなのでどの型でも代入できる
		strList = numList; //OK

	}
	
}
		
		//Number以下の階層は代入できない
		Ex<? super Number> numWildList = new Ex();
		
		Ex<Integer> intList = new Ex();
		Ex<Object> objList = new Ex();
		
		//Number以下の階層であるIntegerのオブジェクトは
		//代入できない
		numWildList = intList;//コンパイルエラー
		numWildList = objList;//ok

型情報について

  • コンパイルした時に型情報は消えて、上限境界の型に置換されている。
  • 下記コードがコンパイルされると型情報部分は全てNumberに置き換わる。
    実行時に型情報は取得できない
class Ex <T extends Number> {
	public void method (T x){
		System.out.println(x);
	}
}
  • ArrayListクラスを記述する時
    ArrayList<T>(size)
    と記述できる
  • しかし
    T[size]
    は実行できない。