2011-11-14 2 views
2

Я не понимаю, почему компилятор не видит, что литье безопасно, когда параметризованный тип определяется как расширение базового класса. Вот примеры бросков, которые кажутся мне такими, как будто они не должны быть лишними. Кроме того, когда я включаю актерский состав, моя IDE (IntelliJ IDEA) предупреждает, что бросок не отмечен, как будто предполагать, что я делаю что-то неправильно. Есть ли идиома, которая позволяет избежать этих бросков и предупреждений? Почему вообще нужны броски, учитывая, что в заявлении указано, что тип расширяет базовый класс?Почему Java генерирует общие типы?

class Shape {} 

class Polygon extends Shape {} 

public class Foo<T extends Shape> 
{ 
    Set<Polygon> polygons; 
    // Why must this be cast? 
    Set<T> shapes = (Set<T>) new HashSet<Polygon>(); 

    T getFirst() 
    { 
    // Why must this be cast? 
    return (T) polygons.iterator().next(); 
    } 

    Iterable<T> getShapes() 
    { 
    // Why must this be cast? 
    return (Iterable<T>) polygons; 
    } 
} 

ответ

5

Давайте предположим, что вы инстанцирован свой класс так:

Foo<Circle> circleFoo = new Foo<Circle>(); 

Затем Set<Circle> не может быть безопасно назначен HashSet<Polygon>

В getFirst: Вы не можете безопасно литой Polygon до Circle

И в getShapes: вы не можете безопасно отличить Iterable<Polygon> - Iterable<Circle>.

+0

Улучшенное написание: P –

+0

Я понял это в какой-то момент. Спасибо за лаконичную переподготовку. –

0

В первом примере, Set<T> не является базовым классом HashSet<Polygon>.

Во втором примере тип polygons.iterator().next() равен Polygon, что не совпадает с T.

5

T extends Shape, Polygon extends Shape. Таким образом, нет никаких оснований, что T расширяет Polygon

1

Возможно, вас заинтересует this о Java generics.

В основном,

Box<Integer> and Box<Double> are not subtypes of Box<Number> 
1
Set<T> shapes = (Set<T>) new HashSet<Polygon>(); 

Бросок необходимо как T здесь может быть все, что проходит Shape и вы пытаетесь соответствовать только многоугольники. Circle является shape, но его не Polygon. Лучшей практикой является рассмотрение параметризованных дженериков как уникального класса.

Если java разрешил вышеуказанное без литья, он затем откроет дверь для добавления любых T в set. Представьте, что вы назначили свой Polygon на Set<T>, а затем добавили к нему Circle объектов. Это вызывает множество проблем времени выполнения.

1
// Why must this be cast? 
Set<T> shapes = (Set<T>) new HashSet<Polygon>(); 

Это наименьшее из ваших проблем. Преобразование фактически логически неверно. Set<A> не является подтипом Set<B>, если A и B разные, даже если A является подтипом B. Если у нас были восстановимые дженерики, это приведение не получится.

+0

Я вижу это сейчас. Этот код является правильным только в том случае, если класс 'Foo' создается с параметрами типа' Shape' или 'Polygon'. FWIW, я работаю с api, где аргумент типа 'Class ' передается внутри и внутри метода, который вы вызываете 'clazz.isAssignableFrom (Polygon.class) ', чтобы определить, какие из них безопасны. –

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