JAva汎用学習ノート

9067 ワード


   JAva汎用型はJDK 1.5から出てきて、自分でも普段は役に立ちますが、ずっと全面的に勉強していません.今日はmyibatis 3.0.1ソースコードを見ていると、汎用型のデザインがたくさん使われているのを見て、自分で汎用型を勉強しました.
 
汎用とは?
    Java SE 1.5以前に汎用型がなかった場合、タイプObjectへの参照によってパラメータの「任意化」が実現され、「任意化」による欠点は、Object参照オブジェクトが「アップモールド」され、オブジェクトの具体的なタイプ情報が失われることであり、このタイプを使用する場合に明示的な強制タイプ変換を行うことである.この変換は,開発者が実際のパラメータタイプを予知できる場合に行うことを要求する.強制タイプ変換エラーの場合、コンパイラはエラーを提示せず、実行時に異常が発生する可能性があります.これはセキュリティ上の危険です.
汎用型の利点は、コンパイル時にタイプのセキュリティをチェックし、すべての強制変換が自動的で暗黙的であり、コードの再利用率を向上させることです.
 
汎用使用のルールと制限
  • 汎用型のタイプパラメータは、カスタムクラスを含むクラスタイプのみであり、単純なタイプではありません.
  • 同じ汎用は、パラメータタイプが不確定であるため、複数のバージョンに対応することができ、異なるバージョンの汎用クラスインスタンスは互換性がありません.
  • 汎用型のタイプパラメータは、複数あり得る.
  • 汎用パラメータタイプでは、などのextends文を使用できます.習慣的に「有界タイプ」と呼ばれています.
  • 汎用パラメータタイプは、ワイルドカードタイプであってもよい.例えばClassclassType = Class.forName("java.lang.String");

  • 汎用的な基本的な使用
        eg 1:汎用型を用いた
    package com.kyle.Generics.ch01;
    
    
    /**
     *       
     * @author kyle
     *
     * @param <T>
     */
    public class SimpleDemo1<T> {
    	private T ob;//        
    	
        public T getOb() {
    		return ob;
    	}
    
    	public void setOb(T ob) {
    		this.ob = ob;
    	}
    
    	public SimpleDemo1(T ob){
        	
        	this.ob=ob;
        }
    	
    	public  void showType(){
    		
    		System.out.println("T      :"+ob.getClass().getName());
    	}
        
    	public static void main(String args[]){
    		//    SimpleDemo    Integer  
    		SimpleDemo1<Integer> intObj=new SimpleDemo1<Integer>(88);
    		//         ob     
    		Integer  intValue=intObj.getOb();
    		intObj.showType();
    		
    		
    		//    SimpleDemo   String  
    		
    		SimpleDemo1<String> strObj=new SimpleDemo1<String>("Hello world");
    		//         ob     
    		String strValue=strObj.getOb();
    		strObj.showType();
    		String str=strObj.getOb();
    		System.out.println("ob is vlaue :"+str);
    		
    		
    	}
        
    
    }

     
    eg 2:汎用実装は使用されていない
    package com.kyle.Generics.ch01;
    
    /**
     *       
     * @author kyle
     *
     */
    public class SimpleDemo2{
    	
    	private Object ob; //           
    	
    	public SimpleDemo2(Object ob) {
    		this.ob = ob; 
    	} 
    	
    	public Object getOb() {
    		return ob;
    	}
    
    	public void setOb(Object ob) {
    		this.ob = ob;
    	}
    
    	
    	
        public  void showType(){
    		
    		System.out.println("Object      :"+ob.getClass().getName());
    	}
        
        public  static void main(String args[]){
        	SimpleDemo2  intObj=new  SimpleDemo2(new Integer(88));
                   int intValue=(Integer)intObj; //     Integer
        	intObj.showType();
    
    
        	SimpleDemo2  strObj=new SimpleDemo2(new String("Hello Gen2"));
                   String  strValue=(String)strObj;//     String 
        	strObj.showType();
        	
        }
    
    }
    

     
      上記の2つのDEMOの比較により,汎用性がもたらす使いやすさを直接見ることができる.ここでDEMO 1では,Tがオブジェクトを構築する際に動的に伝達される文字列であると簡単に想定できる.
    SimpleDemo 1intObj=new SimpleDemo 1(88)がIntegerに伝わると、private Tobはprivate Integer obとなり、SimpleDemo 1strObj=new SimpleDemo 1("Hello world")が伝わるStringとなり、private Tobはprivate String obとなる.Tはタイプ変数に相当し,コンパイラはコンパイル時にこの変数を我々が入力したタイプに置き換える.
     
     
    汎用的な高度な応用
     1.汎用型の使用可能なタイプを制限する
         class GenericsFooのような汎用TはCollectionインタフェースの実装クラスまたはサブインタフェースのみであり、非Collectionインタフェースに入力するとコンパイルエラーが発生する
      注意:ここでの限定はキーワードextendsを使用し、実際のTのタイプCollectionはCollectionインタフェースを実装するクラスであってもよいし、Collectionインタフェースを継承していてもよい. extendsは継承の意味ではなく、限定的な役割を果たしているだけです.
     
     eg: 
    package com.kyle.Generics.ch03;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.LinkedList;
    
    public class CollectionGenFoo <T extends Collection>{
    	
    	private T x;
    	
       public CollectionGenFoo( T x){
        	
        	this.x=x;
        	
        }
    	
        public T getX() {
    		return x;
    	}
    
    	public void setX(T x) {
    		this.x = x;
    	}
    	
    	public static void main(String args[]){
    		
    		/**1
       		*   CollectionGenFoo    ArrayList
       		*    listFoo          
      		* ArrayList     
       		*         new ArrayList()     ArrayList  
       		*/
    
    
    
       		CollectionGenFoo<ArrayList> listFoo = null;
      		 listFoo=new CollectionGenFoo<ArrayList>(new ArrayList());
                                     listFoo.getX();//         ArryList  
     		 /**2
      		 *   CollectionGenFoo    Collection
      		 *    listFoo          
       		 * Collection     
       		 *          new ArrayList() Collection      
       		 *    Collection   
       		*/
    
    
    
       		CollectionGenFoo<Collection> listFoo2 = null;
       		listFoo2=new CollectionGenFoo<Collection>(new ArrayList());
                                  	listFoo2.getX();//         Collection  		
    		  /**3
        		  *      
        		  *CollectionGenFoo<String>        Collection   
         		  */
    
    
    
        		 //CollectionGenFoo<String> listFoo3=null;
       
       
        		/**4
        		*      ,                Collection   
        		*   new CollectionGenFoo<ArrayList>            
        		*  T              
        		*/
    
    
    
           		//CollectionGenFoo<Collection> listFoo4 = null;
       		//listFoo4=new CollectionGenFoo<ArrayList>(new ArrayList());
    	}
    
    	
    }
    

     
     
       この例を通して、私たちは1,2,3,4の3つの声明方式をよく比較して、汎用的な意味を体得しなければならない.
       1.1,2,3から「有界汎用型」という宣言方式を用いる場合、タイプパラメータTはSuperClassのサブクラスまたはSuperClassタイプである必要があることがわかる.そうでない場合は、タイムズ紙をコンパイルします.
           Bound mismatch: The type String is not a valid substitute for the bounded parameter of the type            CollectionGenFooこのエラー.
       2.のTは任意のSuperClassの任意のタイプであってもよいが、特定のタイプを参照して指定すると、インスタンスの汎用タイプは参照と一致しなければならないことが4から分かる. 親子関係は存在しない,すなわちタイプTは前後に2つの異なる値を付与できない.
     
       2.ワイルドカード汎用
         上記の例では、特定の汎用タイプの参照を宣言する場合、対応するインスタンスの汎用タイプは参照の汎用タイプと同じでなければなりません.これにより、複数の汎用タイプのサブクラスインスタンスがある場合、複数の異なる参照、すなわち、参照が具体化され、言い換えれば、汎用タイプが具体化され、だから私たちの引用も具体化されました.では、汎用的な参照を含めるにはどうすればいいのでしょうか.
    任意のインスタンスタイプも受け入れられますか?
     
      eg: 上のDEMOを続け、mainメソッドに次の宣言を加えます.
     
                    /**5
    		 *      CollectionGenFoo<? extends Collection> 
    		 * listFoo5        Collection      
    		 * 
    		 */
    
    		CollectionGenFoo<? extends Collection> listFoo5 = null;
    		listFoo5=new CollectionGenFoo<ArrayList>(new ArrayList());
    		listFoo5=new CollectionGenFoo<LinkedList>(new LinkedList());
    		listFoo5.getX();//          Collection  
    		
    		
    		/**
    		 * CollectionGenFoo<?>       
    		 * listFoo5        Collection     
    		 * 
    		 */
    		CollectionGenFoo<?> listFoo6 = null;
    		listFoo6=new CollectionGenFoo<ArrayList>(new ArrayList());
    		listFoo6=new CollectionGenFoo<LinkedList>(new LinkedList());
    		listFoo6.getX();//          Object  
         
    		/*
    		 *      :
    		 *      ?       ,        
    		 *    Collection   
    		 */
                    /*  :
                      *Bound mismatch: The type String is not a valid substitute for the bounded parameter
                      *<T extends Collection> of the type CollectionGenFoo<T>
                      */
    
      		//listFoo6=new CollectionGenFoo<String>(new String("test"));
                   
    
     
    まとめ:
    1.5から、CollectionGenFooのワイルドカード方式でオブジェクト参照を宣言する場合、参照は異なる汎用オブジェクトインスタンスを受け入れることができるが、このインスタンス汎用の具体的なタイプは失われ、すべてSuperClassタイプに遡及される
     
    2.CollectionGenFooのワイルドカード方式でオブジェクト参照を宣言する場合、参照は異なる汎用のオブジェクトインスタンスを受け入れることができるが、そのインスタンスの汎用の具体的なタイプは失われ、すべてObjectタイプに遡及される.
     
    3.5,6の  新例の汎用型は、SuperClassのサブクラスまたはSuperClassのタイプである必要があります.
     
    4.ワイルドカードの汎用型は、下に制限するだけでなく、上に制限することもできます.例えば、は、タイプがArrayListタイプとその上位親タイプしか受け入れられないことを示します.たとえば、List、Collection
      
     
      3.汎用方法 
        未完...
     
     
    汎用設計の使用シーン