Generic汎用

3775 ワード

Generic汎用--タイプのタイプ
 
      最初の問題は、汎用性とは何か
      文字通りタイプです.汎用型はJava独自の特性ではなく、実際にはJavaの汎用型はある意味で折衷的な実現であり、汎用型のインスピレーションはC++のテンプレート類に由来するが、実現の柔軟性ではC++のテンプレート類とは異なる.
      次のような状況を考慮すると、メソッドを呼び出すときに、パラメータとしてオブジェクトを入力する必要があります.実際に呼び出すと、このパラメータのサブクラスが入力されます.このような状況はよくあります.
 
            void method(Father father) {}

            method(new Son());

      SonはFather類のサブクラスです.Sonは他の親クラスを継承している場合があるかもしれませんが、Javaは単一の継承であるため、SonはFatherクラスを継承できません.この場合、インタフェースの使用を考慮することができます.
            class Son extends OtherFather implements Father ()
            method(new Son());

      インタフェースの使用は単一継承の限界を解消するが、インタフェースを使用しても限界がある場合がある.method()メソッドに具体的なインタフェースタイプを指定するのはFatherであるからである.
      特定のパラメータタイプを指定せずに、必要に応じて指定する方法はありますか?実勢造汎型!
      入門--シンプルな汎用的な使用
      容器類は汎用的に現れる原動力の一つである.See the following sample code:
		List<String> list = new ArrayList<String>(); 
		list.add("add string");
		list.add(new Integer(1)); // Can not compile

     上のコードはコンパイルできませんが、汎用型はコンパイル期間中に入力されたパラメータのタイプが正しいかどうかをチェックします.これもJDK 1.5が汎用型を発売した原因の一つかもしれません.このチェックは合理的で、カッコの内容を削除すればコンパイルできますが、実行時にはCanNotCastExceptionが得られる可能性があります.コンテナは同じタイプのオブジェクトだけを保存するために使用されることが多いです.コンパイル期間中にこのような誤りを避けることができる以上、苦労してやらないわけにはいかない.
      Listは、Stringオブジェクトを保存するListを意味します(この言い方が正しいかどうか分かりません).単にの代わりに1文字を用いることも可能である、Listは、Tタイプのオブジェクトを格納するリストを意味する.
		List<T> list = new ArrayList<T>();

      汎用型はコンテナクラスだけでなく,一般クラス,メソッド,インタフェース,内部クラスなどにも用いられる.以下の声明はすべて正しい.
		class Tuble<A, B, C> {}
		public interface Interface<T> {}
		abstract class Generator<T> {
			T temp;
			T gen() { return temp; }
		}

 
//P.484  The mystery of erease -- bounds, sel-bounding,wildcard, arrays of generic, issue of generic
      Erease--神秘的な「消磁」
      Eeaseの直訳は消去、除去を意味し、ある人は「消磁」と訳した.
            Class clz = List<Stirng>.class; // Can not compile

      上のコードはコンパイルできません.(new ArrayList).getCLass()と (new ArrayList).getCLass()は等しい.ListのタイプがまだList.classであることを知っています.これがereaseです.つまり、実行時にタイプTが「消去」されているようです.
	class EreaseTest {
		void fun() { System.out.print("fun()"); }
	}
	
	class Erease<T> {
		private T obj;
		Erease(T type) {
			this.obj = type;
		}
		void invoke() { obj.fun(); } // Can not compile
	}

      上のコードは明らかにコンパイルできませんが、Tの具体的なタイプを知る前にobj.fun()を呼び出すのは間違っているので、コンパイラはTにfun()メソッドが登録されていることを知らないので、どのようにしてコンパイラにTにfun()メソッドが登録されていることを知らせますか?
	class Erease<T extends EreaseTest> {
		private T obj;
		Erease(T type) {
			this.obj = type;
		}
		void invoke() { obj.fun(); } // Can not compile
	} 

      extendsキーワードで汎用型に境界を指定すると、コンパイラはTに登録されている方法を知るのに十分です.extendsは継承の意味ではなく、Ereaseは、タイプパラメータTがEreaseクラスまたはその任意のサブクラスであることを意味する.
     この点ではC++のテンプレートクラスの実装とは異なり,C++ではTの特定のタイプを知る前にTをメソッド呼び出しを許可する.Javaは1.5以降であるため、1.4以前のバージョンとの互換性も考慮される可能性があります.汎用はコンパイル期間の静的タイプチェックにのみ使用され、実行時には汎用に関するすべての情報が「除去」されます.つまりerease.
      境界を指定するときにワイルドカードを使用できますか?List つまり、任意のEreaseサブクラスのリストであり、彼は「任意のEreaseサブクラスを保存するリスト」とは全く異なる.
      境界を自分自身に指定できます.たとえば、
	class SelfBound<T extends SelfBound> {}

      親パラメータタイプに子が現れる場合、CRG-Curiously Recurring Genericという名前もあります.
	class Father<T> {}

	class Son extends Father<Son> {}

      これはかなり意味があり、親Fatherを子Sonのモデルにすることができます.