2016-05-28 3 views
3
以下のクラスを考える

...なぜ私のリストで指定されていないタイプのリストを返すことができます<T>戻り値の型?


package whoop.deduper; 

/** 
* @author deduper 
* 
*/ 
public class Foo { 

} 

package whoop.deduper; 


import java.math.BigDecimal; 
import java.util.Iterator; 
import java.util.List; 

/** 
* @author deduper 
* 
*/ 
public class FuBar { 

    public int fuBar(){ 

     Bar bar = new Bar(); 

     List<Foo> foos = bar.foos(); 

     int baz = 0; 

     for (Iterator iterator = foos.iterator(); iterator.hasNext();) { 

      BigDecimal foo = (BigDecimal) iterator.next(); 

      baz = foo.intValue(); 

      return baz; 

     } 

     return baz;  

    } 

} 

package whoop.deduper; 

import java.math.BigDecimal; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

/** 
* @author deduper 
* 
*/ 
public class Bar { 

    public <T extends Foo> List<T> foos() { 

     List sketchy = new ArrayList(); 

     sketchy.add(BigDecimal.TEN); 

     return sketchy; 
    } 

} 

package whoop.deduper; 

import static java.lang.System.out; 

/** 
* @author deduper 
* 
*/ 
public class EffedUp { 

    /** 
    * @param args 
    */ 
    public static void main(String[ ] args) { 

     int effedUp = new FuBar().fuBar(); 

     out.println(effedUp + " — But it works!"); 

    } 

} 

...それはなぜ機能するのですか?つまり、ClassCastExceptionやどこかに何かがあると思います!なぜそこにいないのですか?

ここで何が起こっているのかを誰かが明確に書かれた説明に指摘できますか?

ありがとうございます。

+3

この未加工のタイプのために、 '' List sketchy = new ArrayList(); 'ができます。また、あなたのIDEは 'Bar#foos'でその戻り値を警告しなければなりません。 – Tom

答えて

1

List<Foo>という変数を持っていても、実際にはFoosのリストがあるとは限りません。あなたはFoosを引き出すときにのみ確実に行います。あなたはそうではありません。反復子はIterator<Foo>ではなく、どこでもFooにキャストしていません。コンパイラにあなたのためにキャストを実行させると、期待どおりにブレークします。上記のように、あなたが「正常な」ルートで行く場合

List<Foo> foos = bar.foos(); 

    int baz = 0; 

    for (Foo foo : foos) { 
    System.out.println(foo); // ClassCastException 
    } 

は、コンパイラ自体はイテレータを取得し、Fooにすべての要素をキャストし、リストが空でない場合は、したがって、上記のコードは失敗します。

あなたのコードは、raw-typesがどれほど悪いか、そしてなぜそれらを避けるべきかを示しています。あなたは割り当てを行うと

-1
List l = new ArrayList(); 
    List<Integer> ints = l; 

、あなたはints、より何にlのアドレスを入れるためにJavaを教えてくれます。これは実行時にジェネリックがコードから消去されるときに発生します。

ジェネリックは、コンパイラがタイプに関連する可能性のあるエラーを識別しようとすると、コンパイル時にコンパイラによって使用されます。コンパイル時にクラッシュすることはありません。なぜなら、指定されていない値がリスト内に格納されているかどうかわからないからです。実行時にClassCastExceptionでクラッシュするのは、リストに予期しない要素が含まれる場合です(実行時にのみオブジェクトがあるため)。

コンパイル時にこの問題が発生した理由を理解できません。コンパイラがこのようなことに遭遇した場合、私はコンパイルエラーを予期していました。エラーの代わりに警告が表示されます。

割り当てを行うと、I give you a list, doesn't matter what it has inside, you just store itと表示されます。

アドバイスとして、常にリストの種類を指定してください。あなたの場合List<T>。私の経験ではまれなオブジェクトタイプのリストを持つ必要がない限り、これを覚えておいてください。

関連する問題