このエントリーをはてなブックマークに追加

ポイントというか心にとまったことのアウトプットです。

※個人的な重要度のバイアスがかかっているので、「べつにいいかー」と思ってたりすることはメモしてません。

※手を動かして理解したことなど、間違いを含む可能性があります。

※手元の環境は断りがなければ基本はjava 7 をIntelliJ IDEA Ultimate on OSX で動かしてます。


「ジェネリック型」

  • 型名<型名> で新しい型を作るイメージ(あくまでイメージ)

    • 同様のことをしたければ、型名<型名>の組み合わせごとにクラスを作るか、型名でやってしまう
    • 後者は要素を下位クラスへのダウンキャストする必要があるため、実行時例外が発生する可能性あり
    • 型パラメータ E(Element), T(Type), K(Key), V(Value)

    • 型パラメータ、型変数、型引数、パラメータ化された型

      • 型パラメータは定義
      • 型変数は、ジェネリック定義内での変数
      • 型引数は、具体的に渡す型
      • パラメータ化された型は、List<String> など
    • 型変数は、インスタンスフィールド・メソッド系で使える(クラスフィールド・メソッド系では使えない)

    • 内部的にList<Integer>List<String>は、List<Object> を使い回しているだけ

      • 内部的にはObject型のため、ジェネリック内部で、new E() はできない(EはObject型のため)
    • 境界のある型パラメータ

      • Hoge<E extends CharSequence> など
      • 境界型
      • Hoge<E extends Interface1 & Class1 & Interface2> という風に複数指定も可能
    • ジェネリックメソッド(コンストラクタ)

      • ジェネリックメソッドとジェネリック型は独立している。
      • ↑で型パラメータ名が同じだとしても、別の型変数として扱われる
    • public class Gene1<T> {
      
          private T elem = null; //ジェネリック型定義の型変数が利用可能
      
          public void set(T arg){ //ジェネリック型定義の型変数が利用可能
              elem = arg;
          }
      
          public T get(){ //ジェネリック型定義の型変数が利用可能
              return elem;
          }
      
      }
      
      public class Gene2<T> {
      
          private T elem = null;
      
          public <T> void set(T arg){
      //        elem = arg; //コンパイルエラー
          }
      
          public <T> T get() {
      //        return elem; //コンパイルエラー
              return null;
          }
      }
      
      Gene1<String> g1 = new Gene1<>();
      g1.set("test");
      System.out.println(g1.get()); //test
      
      • Gene1とGene2の例から、ジェネリック型の型変数は、クラス全体で利用可能、ジェネリックメソッドの型変数はメソッド内でのみ利用可能で、ジェネリック型の型パラメータ名と同じ型パラメータをとることもできるが、名前の重複で判断できないときはコンパイルエラーになる

      • ダイアモンド演算子(java7から)

      • パラメータ化された型が複雑になる場合(入れ子など)、新しい型をつくったほうがいいかも

      • ジェネリックメソッドの型は<型引数>で指定しなくても、推論される(指定することもできる)

      • 型引数のワイルドカード?

        • List<CharSequence> l = new ArrayList<String>(); //これはコンパイルエラー
        • List<? extends CharSequence> l = new ArrayList<String>(); //これはOK
        • ↑のListに対して、StringやStringBuilderで入出力はできない
        • できるのはCharSequenceでの要素の取り出しのみ
        • ↑の問題を解決するためにList<? super CharSequence>を使うと、StringやStringBuilderでの入力が可能になる
      List<? super CharSequence> lst = new ArrayList<>();
      
      lst.add("String");
      lst.add(new StringBuilder("SB"));
      
      // CharSequence s = lst.get(0); //なぜコンパイルできない?
      
      • ↑のget()ができないのがわからない。。。


      このエントリーをはてなブックマークに追加

      AdSense