【Java基礎知識】汎用詳細

11218 ワード

1.汎用的な概念:
汎用型はJava SE 1.5の新しい特性であり、汎用型の本質的パラメータ化型、すなわち動作するデータ型は1つのパラメータとして指定される.
2.汎用型を使用するメリット:
(1)安全は簡単で、コードの再利用率を高め、コンパイル時にタイプの安全を検査し、すべての強制タイプ変換は自動的で暗黙的である.
(2)タイプは安全で、後方互換性があり、階層がはっきりしていて、性能が高い.
3.タプルクラスライブラリ(出典:『Thinking Java』)
(1)定義:メタグループとは、一対のオブジェクトを直接パッケージ化して格納する単一のオブジェクトを指し、このコンテナオブジェクトは要素の読み取りを許可するが、新しいオブジェクトの挿入を許可しない.
(2)タプルは任意の長さであってもよく、タプル内のオブジェクトは任意の異なるタイプであってもよい.
例:
//  1   ,   1   
class OneTuple<A> {
    //code
}

//  2   ,       
class TwoTuple<A,B> {
    //code
}

4.単純汎用型の定義
(1)汎用クラス:1つ以上のタイプ変数を持つクラス
public class Pair<T> {
    private T first;
    private T second;

    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    public T getFirst() {
        return this.first;
    }

    public void setFirst(T newValue) {
        this.first = newValue;
    }
}

(2)汎用方法:
例:
//      
public class ArrayAlg {
    //...      
    public <T> T getMiddle(T... a) {
        return a[a.length/2];
    }
}

//      
class ArrayListTest {
    public <T> List<T> list() {
        return new ArrayList<T>();
    }
}

(3)汎用インタフェース例:
public interface Generator<T> {
    T next();
}

(4)匿名内部クラスに汎用的に適用する例:
public class Customer {
    public  Generator<Customer> clerk() {
        return new Generator<Customer>() {
            @Override
            public Customer next() {
                return new Customer();
            }
        };
    }
}

5.汎用消去
(1)定義;javaバイトコードには汎用タイプ情報は含まれていない.コンパイラはコンパイル段階で汎用情報を削除し、実行時にタイプ情報を加える.
(2)異なる種類の消去
例:
public class ErasedTypeEquairalence{
    public static void main(String[] args) {
        Class c1 = new ArrayList<String>().getClass();
        Class c2 = new ArrayList<Integer>().getClass();
        System.out.println(c1 == c2);
    }
}

//    : true

(3)リロード中のタイプ消去
例:
class HoldItem <T,V>{

    public void f(List<T> t) {} // error      

    public void f(List<V> v) {}

    public void f(List<T> t,List<V> v) {}
}

6.汎用的な境界
(1)限定タイプ:
汎用的に消去動作があるため,ObjectのtoString(),equals(),hashCode()…メソッドを呼び出すしかないが,制限を加えると,でDogクラスのメソッドを使用できる.
(2)自己限定タイプ:>
クラスF class F extends Access{}を定義すると、このUはAccessのサブクラスでなければなりません(すなわち、uはAccessに関連する必要があります)
7.ワイルドカード
(1)制限付きワイルドカード
List < ? extends Fruit>サブタイプワイルドカードリストスーパータイプワイルドカード
*生産者消費者モデル補助子:PESC(produce-extends consumer-super)
  • リストからTタイプの要素を読み込むには、このリストをは、その後、リストに要素を追加することはできません.
  • Tタイプの要素をリストに追加するには、このリストをは、後で要素を読み取ることができません.
  • リストが生産され、消費される場合は、リストなどの汎用ワイルドカード宣言リストを使用することはできません.

  • 例:
        public <T extends Dog> void get1(List<T extends Dog> list){
            list.get(0);
        }
    
        //error
        public <T extends Dog> void set1(List<T extends Dog> list, Dog dog){
            list.add(dog);
        }
    
        //error
        public <T super Cat> void get2(List<T super Cat> list){
            list.get(0);
        }
    
        public <T super Cat> void set2(List<T super Cat> list, Cat cat){
            list.add(cat);
        }

    例2:Collectionsクラスのcopyメソッドは典型的なPECSモデルであり,以下はcopyメソッドのソースコードである.
    /**
         * Copies all of the elements from one list into another.  After the
         * operation, the index of each copied element in the destination list
         * will be identical to its index in the source list.  The destination
         * list must be at least as long as the source list.  If it is longer, the
         * remaining elements in the destination list are unaffected. <p>
         *
         * This method runs in linear time.
         *
         * @param  <T> the class of the objects in the lists
         * @param  dest The destination list.
         * @param  src The source list.
         * @throws IndexOutOfBoundsException if the destination list is too small
         *         to contain the entire source List.
         * @throws UnsupportedOperationException if the destination list's
         *         list-iterator does not support the <tt>set</tt> operation.
         */
    
        public static <T> void copy(List<? super T> dest, List<? extends T> src) {
            int srcSize = src.size();
            if (srcSize > dest.size())
                throw new IndexOutOfBoundsException("Source does not fit in dest");
    
            if (srcSize < COPY_THRESHOLD ||
                (src instanceof RandomAccess && dest instanceof RandomAccess)) {
                for (int i=0; i<srcSize; i++)
                    dest.set(i, src.get(i));
            } else {
                ListIterator<? super T> di=dest.listIterator();
                ListIterator<? extends T> si=src.listIterator();
                for (int i=0; i<srcSize; i++) {
                    di.next();
                    di.set(si.next());
                }
            }
        }

    (2)無境界ワイルドカード
    8.制約と限界
    (1)基本データ型でタイプパラメータをインスタンス化できない(2)ランタイムタイプクエリ元のタイプ(3)パラメータタイプを作成できない配列にのみ適用
    例:
    Pair<String>[] table = new Pair<String> [10];   //error

    解決策:*ArrayList*を使用するツールクラスArrays.asList()
    (4)Varargs警告
    抑制警告:@SuppressWarnings("unchecked")またはsafe Varargs
    (5)タイプ変数をインスタンス化できない(6)汎用クラスの静的コンテキストでタイプ変数が無効(7)汎用クラスのインスタンスを投げ出したり捕獲したりできない(8)消去後の衝突を防ぐ