2017-02-22 16 views
2

У меня есть класс с дженериками. Я знаю, что информация об общем типе разделяется во время выполнения, но это связано со связанным типом. Я думал, что при компиляции java.lang.Object заменяется связанным типом. Если я знаю, что все всегда будет как минимум Animal, то почему компилятор оставляет его как Object? Есть ли что-то, что мне не хватает, что бы эта работа, как я хочу? В частности, этот последний цикл for в основном методе имеет проблему времени компиляции.Что такое стирание ограниченного родового типа?

Спасибо!

public static void main(String[] args) throws Exception { 

    Litter<Cat> catLitter = new Litter<>(); 
    for(Cat cat : catLitter) {} 

    Litter<Animal> animalLitter = new Litter<>(); 
    for(Animal animal : animalLitter) {} 

    Litter litter = new Litter(); 
    for(Animal animal : litter) {} // Type mismatch: cannot convert from element type Object to Animal 
} 

public class Litter<T extends Animal> implements Iterable<T>{ 
    @Override public java.util.Iterator<T> iterator() { 
     return new LitterIterator(); 
    } 

    class LitterIterator implements java.util.Iterator<T> { 
     @Override public boolean hasNext() { return false; } 
     @Override public T next() { return null; } 
    } 
} 

public class Animal {} 
public class Dog extends Animal{} 
public class Cat extends Animal{} 
+3

Если вы включите все предупреждения компилятора, вы увидите, что вы используете необработанный тип для 'litter', что существенно заставляет компилятор игнорировать существование дженериков полностью для этого оператора. – VGR

+0

Если тип не указан, вся общая информация удаляется - вы остаетесь только с Object. – Bohemian

+0

Это не так просто @Bohemian. Ограниченный тип немного изменяет правила. Как показывает Сотириус, метод экземпляра, который обычно возвращает T, когда T расширяет Animal, по-прежнему будет возвращать Animal по необработанному типу. Моя путаница в том, почему Итератор не параметризуется Animal. – bmauter

ответ

4

Обязательный Перенаправление:

поведение вы ожидали бы применить к чему-то вроде

public class Litter<T extends Animal> implements Iterable<T>{ 
    public T get() {return null; /* or whatever */} 
    ... 
} 

и

Litter litter = ...; // raw type 
Animal animal = litter.get(); // compiles fine 

Поскольку Litter является raw type и

типа конструктора (§8.8), метод экземпляра (§8.4, §9.4), или нестатического поля (§8.3) продукта в виде сырья типа C, что не наследуются от его суперклассов или суперинтерфейсов является исходным типом, который соответствует стиранию его типа в родовой декларации, соответствующей C

и с

Стирание переменной типа (§4.4) является стиранием его левого края.

то метод get появляется как

public Animal get() {...} 

к коде с использованием сырьевого Litter типа.

Что касается Litter#iterator() однако, его возвращаемый типа Iterator<T> и так как

стирания параметризованного типа (§4.5) G<T1,...,Tn> является |G|.

его стирание всего лишь Iterator. Метод Iteratornext() затем стерт в

public Object next() {...} 

так очевидно, возвращаемое значение не может быть присвоено переменной типа Animal.

Есть ли что-то, что мне не хватает, что сделало бы эту работу, как я хочу?

Не с сырыми типами, нет.

+0

Спасибо, этот ответ очень полезен. Я все еще борюсь с тем, как это имеет смысл. Ваша первая цитата из JLS заставила бы меня подумать, что метод get() вернет Object, а не Animal, как в вашем примере. (Я знаю, что вы правы, я дважды проверял с помощью компилятора.) Метод get() объекта объекта необработанного помещика возвращает Animal, но его метод iterator() возвращает необработанный Iterator (вместо Iterator ). Как это имеет смысл? Когда я просматриваю список доступных мне методов в Eclipse, это путает. – bmauter

+0

Исходный тип должен быть удален в Java в целом, поскольку он нарушает общее предположение кода. Вероятно, это было добавлено для обратной совместимости, но, на мой взгляд, это было пропущенное решение. – MaxZoom

+0

@bmauter Извините, я тогда не видел вашего комментария. Это разница между стиранием 'T' (который является« Animal') и стиранием «Iterator », который является «Итератором». Затем «Итератор» 'next' также должен быть удален, так как вы обращаетесь к нему по необработанному значению. Стирание его параметра типа 'E' является' Object', потому что оно неограничено. –

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