Java汎用型パラメータの限界

12343 ワード

さぎょう
1.制限タイプパラメータのタイプ
要素タイプがIntegerの対偶にアクセスするクラスIntegerPairを定義するには、次のように書くことができます.
public class IntegerPair<T extends Integer>
{
   public IntegerPair() { first = null; second = null; }
   public IntegerPair(T first, T second) { this.first = first;  this.second = second; }

   public T getFirst() { return first; }
   public T getSecond() { return second; }

   public void setFirst(T newValue) { first = newValue; }
   public void setSecond(T newValue) { second = newValue; }

   private T first;
   private T second;
}

タイプパラメータ後のextendsキーワードはTの上界がIntegerタイプであることを示し、コンパイラはタイプ消去段階でTをIntegerに置き換え、生成したバイトコードは以下のようになる.
Compiled from "IntegerPair.java"
public class generic.bound.IntegerPair {
  public generic.bound.IntegerPair();
    descriptor: ()V
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: aload_0
       5: aconst_null
       6: putfield      #2                  // Field first:Ljava/lang/Integer;
       9: aload_0
      10: aconst_null
      11: putfield      #3                  // Field second:Ljava/lang/Integer;
      14: return

  public generic.bound.IntegerPair(T, T);
    descriptor: (Ljava/lang/Integer;Ljava/lang/Integer;)V
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: aload_0
       5: aload_1
       6: putfield      #2                  // Field first:Ljava/lang/Integer;
       9: aload_0
      10: aload_2
      11: putfield      #3                  // Field second:Ljava/lang/Integer;
      14: return

  public T getFirst();
    descriptor: ()Ljava/lang/Integer;
    Code:
       0: aload_0
       1: getfield      #2                  // Field first:Ljava/lang/Integer;
       4: areturn

  public T getSecond();
    descriptor: ()Ljava/lang/Integer;
    Code:
       0: aload_0
       1: getfield      #3                  // Field second:Ljava/lang/Integer;
       4: areturn

  public void setFirst(T);
    descriptor: (Ljava/lang/Integer;)V
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #2                  // Field first:Ljava/lang/Integer;
       5: return

  public void setSecond(T);
    descriptor: (Ljava/lang/Integer;)V
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #3                  // Field second:Ljava/lang/Integer;
       5: return
}

IntegerPairのサポートタイプはIntegerとそのサブタイプの要素であるため、BoundTestはコンパイルされません.
public class BoundTest {
    public static void main(String[] args) {
        IntegerPair integerPair = new IntegerPair();
        integerPair.setFirst("text");
    }
}

IntegerParのタイプパラメータTの限界はInteger、IntegerPair setFirstの署名は(Ljava/lang/Integer;)Vであるため、BoundTestをコンパイルする際にエラーが発生します.integerPar setFisrtがStringタイプであるためです.
BoundTest.java:12: error: incompatible types: String cannot be converted to Integer
        integerPair.setFirst("text");
                             ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

2.汎用アルゴリズムの実現
NaturalNumberに示すように、タイプパラメータによって境界を呼び出す方法があります.
public class NaturalNumber<T extends Integer> {

    private T n;

    public NaturalNumber(T n)  { this.n = n; }

    public boolean isEven() {
        return n.intValue() % 2 == 0;
    }

    // ...
}

タイプパラメータTの限界はIntegerであるため、initValue.のようにT上でIntegerを呼び出すことができる方法が汎用アルゴリズムを実現する鍵である.リスト内の要素より大きいものを求めるアルゴリズムを検討します.
public static  int countGreaterThan(T[] anArray, T elem) {
    int count = 0;
    for (T e : anArray)
        if (e > elem)  // compiler error
            ++count;
    return count;
}

演算子>はshort,int,long,double,float,byte,charなどの基礎データ型でのみ操作でき、Objectに対して>操作できないため、コンパイラはエラーを報告します.
GenericAlgorithm.java:19: error: bad operand types for binary operator '>'
            if (e > elem)  // compiler error
                  ^
  first type:  T
  second type: T
  where T is a type-variable:
    T extends Object declared in method <T>countGreaterThan(T[],T)
1 error

この問題はcountGreaterThanメソッドが通用しないことを招く.タイプパラメータに限界を付けると、この問題をうまく解決できます.
public interface Comparable<T> {
    public int compareTo(T o);
}

新しい汎用アルゴリズムは次のとおりです.
public static > int countGreaterThan(T[] anArray, T elem) {
    int count = 0;
    for (T e : anArray)
        if (e.compareTo(elem) > 0)
            ++count;
    return count;
}

マルチリミット
1つのタイプのパラメータには複数の境界があり、次のように表現できます.

タイプ変数Tのタイプは、境界リストのいずれかのタイプのサブクラス.zhu'ru注意:タイプパラメータの境界がクラスである場合、MultiBounds.javaに示すように、境界リストの最初の位置に置く必要があります.
public class MultiBounds {
    static class A {
        public void a() {

        }
    }

    interface B {
        void b();
    }

    interface C {
        void c();
    }


    static class D  {
        public void d(T t) {
            t.a();
            t.b();
            t.c();
        }
    }

    public static void main(String[] args) {
        D d = new D();
        d.d(new A());
    }
}

Dのタイプパラメータの境界クラステーブル音が次のように明示されている場合、Bはインタフェースであり、クラスAは境界リストの2番目の位置に置かれているため、コンパイラはエラーを報告する.
D  

小結
タイプパラメータの限界はタイプ変数のタイプを制限するために使用することができ、汎用アルゴリズムを実現する鍵である.タイプ変数には複数の境界があります.