2012-01-28 10 views
1

"Head First Java"を読んでいました。ジェネリックスに関する質問があります。Java - 一般的な引数を受け入れるメソッドにポリモーフィックにオブジェクトを渡す

本書では、多型的にサブタイプをArrayListを受け入れるメソッドに渡すことができないと正しく述べていました。以下の例 -

public class Animal { 

} 

public class Dog extends Animal { 

} 

public class Cat extends Animal { 

} 

public class AnimalTester { 
    public static void main (String[] args) { 
     new AnimalTester().go(); 
    } 


    public void go() { 
     List<Animal> animalList=new ArrayList<Animal>(); 
     List<Dog> dogList=new ArrayList<Dog>(); 
     processAnimals(animalList); // this would compile 
     processAnimals(dogList); // this would not compile 
    } 

    public void processAnimals(List<Animal> animalList) { 

    } 

} 
上記ジェネリック医薬品の使用によって固定することができる。しかし

-

public <T extends Animal> void processAnimals(List<T> animalList) { 

} 

しかし、何がリストに追加しようとする場合は、上記の場合には、コンパイラは(例外をスローしますこれは本に記載されています)。私はIDEを使って試してみましたが、例外がスローされました。この本はまた、不正なオブジェクト(例えば、cat)がリストに追加されないようにすることを言いました(私たちの場合はdogList)。

しかし、私は(T)を使ってcat/dog/animalオブジェクトをキャストすることでこれを行うことができます。

public <T extends Animal> void processAnimals(List<T> animalList) { 
    animalList.add(new Animal()); // compilation Error 
    animalList.add(new Dog()); // compilation Error 
    animalList.add(new Cat()); // compilation Error 
    animalList.add((T) new Cat()); // works and I can also cast it back 
            // to Cat and get a Cat object 
} 

Javaクリエイターが例外を投げた理由の全体は、誤ったオブジェクトをリストに追加しないでください。しかし、プログラマがそれを明示的にキャストし、「私が何をしているか知っている」と言っているので、Javaはそれを許していますか?

+3

非常に説明的なタイトルではありません。 –

+0

申し訳ありません、今すぐ変更しようとしました。 –

答えて

3

基本的に、コンパイラで終了しました。

ジェネリックス全体について考える必要があります。彼らはコンパイル時の安全のためだけにあります。彼らはあなたに何も買わない。実行時には、タイプ消去のために、あなたはまだ何かを保持できるList<Object>を扱っています。あなたが明示的に何かをキャストしようと決めたなら、コンパイラはあなたを推測しません。あなたは潜在的な危険をコンパイル時から実行時に移動しました。これはあなたの選択です。

+0

魔法の言葉を言って+1: "タイプ消去" ...おめでとう: – Paul

+0

おかげでrfeak。 Javaの配列は他のものを追加することはできません - 私はランタイム例外を取得しますが、これはArrayListの場合と異なります(実行時にすべてがオブジェクトとして扱われるため)。この特定のコンテキストで配列と配列リストの動作が異なる必要がある理由はありますか? –

+0

これは下位互換性を維持するためですが、コンパイラがこれを制限する方法がありますか? –

関連する問題