2012-03-29 20 views
4

次のコードをどのようにコンパイルすることも可能ですか?私が見る限り、count関数は2つの異なる型で呼び出されていますが、コンパイラはこのコードを喜んでコンパイルしません。2つの異なる汎用引数を使用して汎用関数を呼び出す場合

public class Test { 
     public static <T> int count(T[] x,T y){ 
       int count = 0; 
       for(int i=0; i < x.length; i++){ 
         if(x[i] == y) count ++; 
       } 
       return count; 
     } 
     public static void main(String[] args) { 
       Integer [] data = {1,2,3,1,4}; 
       String value = "1"; 
       int r =count(data,value); 
       System.out.println(r + " - " + value); 
     } 
} 
+2

Javaのジェネリックスは視覚的なトリックであることを理解する必要があります。コンパイラを使用すると、オブジェクトの種類が削除されます。 Googleの "Javaのタイプの消去"は、汚い詳細を見つける。 – robertvoliva

+0

確かに。私は多かれ少なかれ起こっていたことを知っていましたが、私は理由を知りたいと思っていました。私は、あなたが言ったように、(ジェネリックの)ジェスチャーは "ただの視覚的なトリック"(私はそれを汚いと呼ぶだろう)であることを認識しました。 – Stan

答えて

2

この場合、Tは役に立たない。署名をpublic static int count(Object[] x, Object y)に変更することはできますが、コンパイラが受け入れる引数には何の影響もありません。 (あなたはArrays.fill()の署名は、その署名として使用していることがわかります。)私たちはあなただけのタイプTの引数を持つ単純なケースを考慮した場合

は、あなたがそれを見ることができ、Tの任意のインスタンスは、インスタンスであるため、 Tは常にその上限に推論することができ、以前と同じ引数型を受け入れます。したがって、Tを取り除き、その上限(この場合はObject)を使用することができます。 Javaで

アレイは、同じように動作する:アレイは、共変であるSTのサブクラスである場合、S[]T[]のサブクラスであることを意味します。したがって、上記と同じ引数が適用されます。つまり、型がTT[]の場合、Tはその上限に置き換えることができます。

7

TObjectに上向きに強制されます。 Integer[]は、Object[]にアップキャストでき、StringはアップキャストされてObjectになり、タイプチェックされます。

+2

これに加えて、変数 'r'は実際にはプリミティブ型(オブジェクトではありません)ですが、ここで自動ボクシングが関与しています:) –

0

タイプはそれほど違いはありません。どちらもjava.lang.Objectのサブクラスです。この場合、コンパイラはTがObjectであると仮定します。

2

をあなたがあなたの呼び出しを変更した場合:

List<T>のサブタイプではないList<S>これは共変または反変ではありませんジェネリック型には適用されないことに注意してください。):

int r = Test.<Integer>count(data, value); 

ますコンパイラが不平を言うのを見るでしょう。

1

2つのオブジェクトを一度に渡すと、Tに非常に多くの制約がかかります。これにより、コンパイラはObjectを推論します。幸運にも、単純な回避策があります - オブジェクトを1つだけ渡します。次のようにすると、予想されるエラーが発生します。

public static void main(String[] args) { 
    Integer[] data = { 1, 2, 3, 4 }; 
    String value = "1"; 
    int r = count(value).in(data); 
    System.out.println(r + " - " + value); 
} 

public static <T> Counter<T> count(T obj) { 
    return new Counter<T>(obj); 
} 

public static class Counter<T> { 
    private final T obj; 

    Counter(T obj) { 
     this.obj = obj; 
    } 

    public int in(T[] array) { 
     return in(Arrays.asList(array)); 
    } 

    public int in(Iterable<? extends T> iterable) { 
     int count = 0; 
     for (T element : iterable) { 
      if (element == obj) { 
       ++count; 
      } 
     } 
     return count; 
    } 
} 
+0

私は実際にコードを動作させることに興味がありませんでした(私はそれが醜いと知っています)。私はたいていそれがなぜコンパイルされたのかを知りたがっていました。面白い回避策:-) – Stan

+0

これは非常に巧妙な解決策です! – Genzer

関連する問題