Javaタイプ消去と汎用

5334 ワード

Javaの詳細については、文集「Javaの詳細」を参照してください.
タイプシステム
Liskovリ氏置換の原則は,子クラスが親クラスに置換できることである.
  • Objectの参照を必要とする場合、Stringのオブジェクト
  • に伝達することができる.
  • Stringの参照を必要とする場合、Objectのオブジェクトに転送するには強制的なタイプ変換が必要であり、実行時にClassCastException
  • を投げ出す可能性がある.
    タイプ消去タイプErasure
    Javaの汎用性はコンパイラ階層で実現される.コンパイル生成されたバイトコードには汎用型のタイプパラメータが含まれておらず、タイプパラメータはコンパイル時に削除されます.例えば、ListおよびListは、コンパイル後、いずれもListになる.
    タイプ消去の基本手順:コード内のタイプパラメータを特定のクラスに置き換え、<>の内容を削除します.
    汎用型
  • 型パラメータはクラスのみ、例えばList、単純タイプ、例えばList
  • である.
  • 型のパラメータは、例えばHashMap
  • のように複数あることができる.
    汎用性のメリット
  • コンパイル時により強力なタイプ検出.Javaコンパイラは汎用型に強力なタイプ検出を適用し、コードがタイプセキュリティに違反するとエラーが発生します.コンパイル時エラーの修復は、実行時エラーの修復よりも容易です.実行時エラーが検出されにくいためです.

  • 例えば、方法は、Stringオブジェクトを入力し、Stringオブジェクトを出力し、Integerオブジェクトに強制的に変換するコードである.このコードコンパイルは、Objectのサブクラスであるため、実行時にClassCastExceptionが生成される.
    public static Object setAndReturn(Object obj) {
        return obj;
    }
    
    public static void main(String[] args) {
        Integer i = (Integer) setAndReturn(new String("abc"));
    }
    

    汎用型で実現すると、コンパイル時にタイプの検出が行われます.たとえば、コンパイルエラーが発生します.
    public static  T setAndReturn(T t) {
        return t;
    }
    
    public static void main(String[] args) {
        Integer i = (Integer) setAndReturn(new String("abc"));
    }
    
  • は、自動および暗黙的なタイプ変換を提供する、例えば、関数が戻るときに表示する必要のないタイプ変換setAndReturn(new Integer("123"));
  • を提供する.
    public static  T setAndReturn(T t) {
        return t;
    }
    
    public static void main(String[] args) {
        //       = setAndReturn(new Integer("123"));
        Integer i = setAndReturn(new Integer("123"));
    }
    
  • は、C++のテンプレート
  • と同様の汎用アルゴリズムを実現する.
    汎用的な奇妙な特性
  • 汎用クラスには、独自のClassオブジェクトはありません.すなわち、List.classは存在せず、List.classのみが存在する.
  • 汎用クラスの静的変数は、すべてのインスタンスで共有される.
  • 汎用クラスのタイプパラメータは、異常処理のcatchでは使用できません.例外処理はJVM実行時に行われるため、タイプパラメータは消去されます.

  • VS >
    相違点:
  • は汎用的な定義に用いる、例えばclass MyGeneric {...}
  • である.
  • >は、汎用的な宣言、すなわち、汎用的な使用、例えばMyGeneric> g = new MyGeneric<>();
  • に用いる.
    同じ点:上界と下界を指定できます.たとえば、class MyGeneric {...} class MyGeneric {...}MyGeneric extends Collection> g = new MyGeneric<>(); MyGeneric super List> g = new MyGeneric<>();
    汎用クラス
    例:
    public class Generic_Test {
        public static void main(String[] args) {
            MyGeneric g1 = new MyGeneric(new String("123"));
            g1.print();
    
            MyGeneric g2 = new MyGeneric(new Integer("123"));
            g2.print();
        }
    }
    
    class MyGeneric {
        private T t;
    
        public MyGeneric(T t) {
            this.t = t;
        }
    
        public void print() {
            System.out.println(t.getClass().getName());
        }
    }
    

    Java 7の汎用タイプ推定の改善
    上記のコードでは、MyGeneric g1 = new MyGeneric(new String("123"));です.宣言と付与の両方に汎用型を付ける必要があることがわかる.
    Java 7では、この方法が改良され、MyGeneric g1 = new MyGeneric<>(new String("123"));という文を使用して宣言および付与することができる.この文では、コンパイラは、変数宣言時の汎用タイプに基づいて、MyGenericをインスタンス化した汎用タイプを自動的に推定する.
    汎用メソッド
    例:
    public static  void print(T t) {
        System.out.println(t.getClass().getName());
    }
    
    public static void main(String[] args) {
        print(new String("123"));
        print(new Integer("123"));
    }
    

    汎用クラスの使用
  • などの特定のタイプを指定します.
  • は、Listなどの未知のタイプを指定します.List>List>に等しくないのはList, :
    List list1 = new ArrayList();
    list1.add(1); //     
    
    List> list2 = new ArrayList();
    list2.add(1); //     
    

    • Stringのサブクラスであるが、ObjectListでなければコンパイルは である.
      public static void f(List list) {
      }
      
      public static void main(String[] args) {
          List list = new ArrayList();
          f(list); //     .
      }
      
    • じパラメータタイプの クラスの は、 クラス の に する. えばList
      : 。
      List List>Listのサブクラスである.
    • タイプ でワイルドカードCollectionが される 、そのサブタイプは2つの で することができる. えば、?がディメンション1に する:Collection extends Number>がディメンション2に する:List extends Number>の2つのディメンションが に する:Collection
    • :Java 8の しい ( ) の タイプ java 8 (generics)