2014-04-08 2 views
0

В случае массивов можно сказать Animal[] animals = new Cat[10];Почему так много разборчивых правил о дженериках Java?

Но, используя общий синтаксис, мы не можем сказать, List<Animal> is aArrayList<Cat>.

List<Animal> может ссылаться на любую полиморфную базовую коллекцию только животных и ничего другого ради безопасности типов.

public void foo() { 
    Cat[] cats = {new Cat(), new Cat()}; 
    addAnimals(cats); 
} 

public void addAnimal(Animal[] animals) { 
    animals[0] = new Dog(); // No compile time error. But ArrayStoreException 
          // at runtime as the JVM knows the type of animals. 
} 

Если бы генерик были неявно полиморфными, в худшем случае, даже если мы добавим неправильный элемент в коллекцию и сделать некоторые вещи, похожие на тот, как в приведенной выше коде, в лучшем случае мы получим ClassCastException (или какое-либо другое исключение), который также останавливает поток программы, например ArrayStoreException?

Я читал, что в случае дженериков из-за стирания типа JVM ничего не знает о типе коллекции и, следовательно, не может генерировать исключение, например ArrayStoreException.

Мой вопрос: почему это много времени защиты времени в случае typed коллекций? Почему так много разборчивых правил с дженериками? Пожалуйста, предоставьте правильное понимание.

+0

Является ли ваше животное абстрактным классом или интерфейсом? – OrhanC1

+3

Потому что, ну, тип безопасности повышает надежность, а Java - это язык, безопасный для типов. Вы можете использовать JavaScript, Groovy или любой другой динамический язык, если вы предпочитаете менее безопасные для использования языки. В Java мы предпочитаем не иметь собак в «List ». –

+0

Потому что лучше ловить ошибки во время компиляции, а не пропускать их во время выполнения. – anonymous

ответ

1

Это распространенное заблуждение, что дженерики были представлены как расширение существующего полиморфизма Java. Это неправда. Были введены дженерики Java, позволяющие использовать Проверка типа времени компиляции.

interface Species { 

} 

class Animal implements Species { 

} 

class Cat extends Animal { 

} 

class Dog extends Animal { 

} 

class Plant implements Species { 

} 

class Tree extends Plant { 

} 

public void test() { 
    System.out.println("Hello"); 
    List<Animal> animals = new ArrayList<>(); 
    animals.add(new Cat()); 
    animals.add(new Dog()); 
    // Not allowed. 
    //animals.add(new Tree()); 

    // The old way. 
    List beasts = new ArrayList(); 
    beasts.add(new Cat()); 
    beasts.add(new Dog()); 
    // Allowed - only caught at run time and difficult to find. 
    beasts.add(new Tree()); 

    // The interface way. 
    List<Species> living = new ArrayList(); 
    living.add(new Cat()); 
    living.add(new Dog()); 
    // Allowed. 
    living.add(new Tree()); 

} 

Целью дженериков было сделать легко определить точно, какой класс объект может обрабатывать и иметь, что проверяются во время компиляции.

Дженерики также использовали интерфейсы намного опрятно.

0

Идея дженериков должна быть Тип сейфа. Если List<Cat> был подкласс List<Animal> - это нарушило бы его:

List<Cat> cats = new ArrayList<Cat>(); 
List<Animal> animals = cats; 
animals.add(new Dog()); 

выше компилируется просто отлично - но то, что случилось бы, теперь, когда вы пытаетесь получить доступ к cats? он будет иметь элемент, который не является Cat, и, например:

for (Cat c : cats) { ...} 

потерпит неудачу.

+2

Я думаю, вы имели в виду 'animals.add (new Dog());'? – anonymous

+0

@ anonymous Спасибо. Конечно, да. – amit

+0

@amit Список всех категорий животные = кошки; будет компилироваться? –

Смежные вопросы