2015-11-16 9 views
5

一見類似したコードの異なるコンパイルの結果を理解しようとしています。 List<Object>List<T>にキャストすることは可能ですが、Tがコンクリートクラスで結合されていない場合にのみ可能です。だから、class Test<T extends BigDecimal>class Test<T extends BigDecimal & CharSequence>class Test<T>ならびにclass Test<T extends CharSequence>ではなく...クラスの型パラメータのリストへのオブジェクトのキャストリスト

List<Object> bis = new ArrayList<>(); 

次コンパイルを与えられました。

List<T> result = (List<T>) bis; 

だから、違いはクラス型とインタフェース型で囲まれたTのためにから来たのでしょうか?

編集

要求ごとにいくつかの完全なコード。これは9行目のコンパイラの警告でコンパイルされます。resultの項目を操作しているかのように、実際にはCharSequenceというインスタンスであるかのように安全ではありません。結果はClassCastExceptionです。

public class Sandbox<T extends CharSequence> { 

    public static void main(String[] args) { 
     new Sandbox<CharSequence>().foo(); 
    } 

    private void foo() {  
     List<Object> bis = Arrays.asList(Integer.valueOf(1)); 
     List<T> result = (List<T>) bis; 
     System.out.println(result); 
    } 
} 

しかし、これはまったくコンパイルされません:9行目で

public class Sandbox<T extends BigDecimal> { 

    public static void main(String[] args) { 
     new Sandbox<BigDecimal>().foo(); 
    } 

    private void foo() {  
     List<Object> bis = Arrays.asList(Integer.valueOf(1)); 
     List<T> result = (List<T>) bis; 
     System.out.println(result); 
    } 

} 

コンパイラエラー:List<T>List<Object>をキャストすることはできません。 Arrays.asList(Integer.valueOf(1))はあなたがCannot cast List<Object> to List<T>を得る理由です、List<Integer>を返しますので、

+1

コードがさらに必要です。あなたのために失敗した正確な行を教えてください。 – markspace

+1

'List 'を 'List 'にキャストするのは型安全ではありません。 'T'は' Object'とは異なる値をとることができます。インタフェースタイプ* vs *。クラス型は関係ありません。任意のJavaコンパイラが問題を診断するかどうかは、異なる質問です。 –

+1

'T extends CharSequence'バージョンはコンパイルされません。 https://ideone.com/ySVuPr –

答えて

0

も、このList<Object> bis = Arrays.asList(Integer.valueOf(1));は明らかにコンパイルされません。

第2のケースでは、eclipseはT extends CharSequenceで馬鹿げてコンパイルしますが、オンラインコンパイラでチェックしてコンパイルしないので、おそらくそれはeclipseのバグです。

+0

実際には、 '一覧ビス=は、Arrays.asList(整数。 valueOf(1)); 'はコンパイルします。 javaの以前のバージョンでは、唯一の明示的な型の引数 '一覧ビス=アレイでコンパイルします。 asList(Integer.valueOf(1)); '、今Javaは型推論が改善され、それがいずれかのように動作します。 –

+1

@Paulウル右、私はこれが最初の答えであると、もともと私はいくつかの言語の組み込み関数を理解していないと信じにもかかわらず、私が探していた結論であるように思われ、不正な動作としてEclipseのコンパイラを言及JDK7 – Ramanlfc

+0

を使用。 @PaulBoddingtonも貴重なコメントをいただきありがとうございます。 – gdabski

0

このような現象を理解するための鍵は、型消去が実際に行っていることを理解することです。 は、実行時にタイプパラメータをで削除しているという一般的な信念にもかかわらず、実際にはこの方法では正しく動作しません。それは何ですか - は、をパラメータ境界として宣言します。どこでもList<T>と入力してください。Tには範囲があり、実際にはList<[lower-bound-of-T]>に縮小されています。そしてCharSequenceないObjectので、(それは少なくともList<CharSequence>を意味する)、List<Object>List<T>にキャストすることはできません

これはなぜ起こりますか? 、

public class Sandbox<T extends CharSequence> { 
    void bar(T param) { 
     //... 
    } 
} 

bar(T)T年代とTを受け入れることができCharSequenceを拡張するものがあるので、基本的には、実行時にこれを効果的

void bar(CharSequence param) { 
    //... 
} 

として動作します。想像して、あなたのSandboxクラスは、型Tのパラメータを受け取るメソッドを持っていますしたがって、それは単純なObjectを受け入れることができません。そのため、空でない下位パラメータの既存のバインドだけがフリーキャストを制限する理由です。...<Object>

さらに、ワイルドカード?型パラメータはあなたの心を爆破することができます。コンパイラには "のようなものはありませんが、私はそれが何であるか分かりませんが、私はそれがすべての境界を満たすと確信しています"と言います。かなり奇妙な、その事実を含めて、あなたはそれに(ほとんど?)何かをキャストすることができますので、それがジェネリックを持つクラスを設計するために来るとき

List<Object> bis = Arrays.asList(Integer.valueOf(1)); 
    List<T> result = (List<T>) (List<?>) bis; 

だから、あなたは非常に、非常に注意しなければならない可能になります。

関連する問題