2012-03-23 8 views
5

私はJava GenericsとCollectionsという本をMaurice Naftalin、Philip Wadlerによって読んでいました。最初の2つの章では、私の頭が疑問にぶち壊されてしまいました。私は答えを理解することができませんでした。タイプパラメータのデータ型は共分散および反分散でどのように決定されますか?

機能 'コピー' の呼び出し中に
public static <T> void copy(List<? super T> dst, List<? extends T> src) { 
for (int i = 0; i < src.size(); i++) { 
dst.set(i, src.get(i)); 
} 
} 


List<Object> objs = Arrays.<Object>asList(2, 3.14, "four"); 
List<Integer> ints = Arrays.asList(5, 6); 
Collections.copy(objs, ints); 
assert objs.toString().equals("[5, 6, four]"); 


第一パラメータ:?=オブジェクト
第二パラメータ:?

コールで

=整数

しかし、データ型は何ですかTの?消去の実装に基づいてjvmによってどのように決定されますか?

その本の中で言われている:行で Collections.copy(OBJ、int型)、型パラメータTが数であると解釈されます。 OBJSがリストに< ?スーパー番号>(スーパーによって要求されるように、オブジェクトは、番号のスーパータイプであるため)と int値がリストに<整数型を持つリストのサブタイプである<オブジェクト>を、型を持つので、呼が許可されています>(リストのサブタイプである)< ?は、>を継承します(Integerは、extendsワイルドカードで必要とされるように、Numberのサブタイプです)。

しかし、整数の両方のシリアライズとComparableを実装して、Numberクラスとオブジェクトクラスを拡張するからアプルも直列化と同等のスーパータイプです。

なぜ、Tは、Numberの代わりにSerializableまたはComparableと見なされますか?なぜなら、Substitution Principleはそれをとることができるからです。

ありがとうございます。

+0

なぜTである正確に何も問題ないです 最も具体的なタイプを選ぶことができますか?ジェネリックはコンパイル時の型チェックにしか使われないので、コンパイラは*働くT *があることに気を付けるべきです。戻り値の型をvoidからTに変更すると、それ以上の違いはありません。 – newacct

答えて

1

Tは、引数に基づいて決定されるが、同様に、明示的に指定することができるという事実にあります。したがって、それはComparableとSerializableになります。

これらのすべてが有効です。全くタイプが整数を伴う方法<? extends Integer>に選ばれている指定されていない

 Collections.<Number>copy(objs, ints); 
    Collections.<Comparable>copy(objs, ints); 
    Collections.<Serializable>copy(objs, ints); 
    Collections.<Integer>copy(objs, ints); 

    Collections.copy(objs, ints); // implicitly Integer 

は取り扱わと「シンプル」からjava documentation

+0

しかし私の関数では、Tのデータ型はNumberです。 どのように知りたいですか?明示的に宣言されていれば、それはシリアライズ可能なものと同等のものがあります。 –

+0

あなたはその番号をどう思いますか?これらのタイプのどれでもかまいませんが、Numberはより良い例です。 – Andrejs

+0

あなたは正しいかもしれませんが、言語は「Tは数字になる」と言います。 だから、言語はTが実際には数字であると言及していません。そうかもしれない。しかしそれでも問題はそのままです。 Tのデータ型は明示的にパラメータを言及せずに、私の質問に記載されている関数を呼び出しますか? –

-1

オブジェクトクラスこれは、真のシリアライズと比較できないでも
直列化と同等のスーパータイプであるインタフェースであり、オブジェクトとは関係を持ちません。

さらに、super ?は、extends ? の正確な逆数です。つまり、インターフェイスに適用できません。 これはインターフェイスに適用できます。

? extends Tと書くと、? is an unknown subtype of T, probably T itselfを意味します。私はJVMがT底を解決すると信じています。つまり、Tは実際にはIntegerではありません。Number(私が間違っていると私を修正します)。

はその後

Collections.copy(objs, ints) 

Collections.<Integer>(objs, ints) 
+0

これはTをIntegerとして解決します。 – benmmurphy

+0

私は分かりません。どうか説明できますか? – UmNyobe

+0

戻り値の型を変更したことを示す回答を追加しました。戻り値の型をコンパイラでbarfに強制するために、コンパイルエラーを追加しました。 – benmmurphy

3

http://docs.oracle.com/javase/specs/jls/se7/jls7.pdf

に説明されていますJLSは、生成するすべての制約を満たす最も具体的なタイプを選択するとします。実引数に基づいて

15.12.2.7推測する型引数

スーパータイプの制約T:> XソリューションはT上のいくつかのような制約を、私たちができる考えるとXの1 のスーパータイプであることを意味し タイプのパラメータは、すべての制約のメンバーでなければならないため、それぞれの制約によって暗示されるスーパータイプのセットを と交差させます。私たちは、その後、交差点

Copy.java:11: incompatible types 
found : java.lang.Integer[] 
required: java.lang.String[] 
    String[] res = copy(Arrays.<Object>asList(2, 3.14, "four"), Arrays.asList(5, 6)); 
        ^
1 error 
➜ /tmp cat Copy.java 
import java.util.*; 
public class Copy { 
public static <T> T[] copy(List<? super T> dst, List<? extends T> src) { 
    for (int i = 0; i < src.size(); i++) { 
     dst.set(i, src.get(i)); 
    } 

    return null; 
    } 
    public static void main(String[] args) { 
    String[] res = copy(Arrays.<Object>asList(2, 3.14, "four"), Arrays.asList(5, 6)); 
    } 

} 
+0

しかし、これは異なっています。文字列[]を返すようにコピーを強制していますので、TをStringにする必要があります...これは関連していません。 – UmNyobe

+0

私はTを文字列にしているわけではありません。コンパイラは実際にはStringではないと不平を言っています。私は、戻り値の型と意図的な型のエラーを追加して、コンパイラを騙して、Tの型が何であるかを明らかにしました。 "found:java.lang.Integer []" ..戻り値の型から配列型を削除する必要がありましたが、そこにあります。 – benmmurphy

+0

しかし、私はまだそれを得ることはできません、どのように決定されますか? 決定の流れを説明できますか?Comparable、Serializable、NumberおよびInegerの3つのオプションの間でどのようにchosingですか? –

関連する問題