Почему Java вынуждает приводить универсальные типы? - PullRequest
2 голосов
/ 14 ноября 2011

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

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;
  }
}

Ответы [ 6 ]

5 голосов
/ 14 ноября 2011

Давайте предположим, что вы создали экземпляр своего класса следующим образом:

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

Тогда Set<Circle> нельзя назначить безопасно HashSet<Polygon>

В getFirst: вы не можете безопасно разыгратьPolygon до Circle

И в getShapes: вы не можете безопасно разыграть Iterable<Polygon> до Iterable<Circle>.

5 голосов
/ 14 ноября 2011

T расширяет форму, полигон расширяет форму. Таким образом, нет причины, по которой T расширяет Polygon

1 голос
/ 15 ноября 2011
// Why must this be cast?
Set<T> shapes = (Set<T>) new HashSet<Polygon>(); 

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

1 голос
/ 14 ноября 2011
Set<T> shapes = (Set<T>) new HashSet<Polygon>();

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

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

1 голос
/ 14 ноября 2011

Возможно, вам будет интересно прочитать это о дженериках Java.

В основном

  Box<Integer> and Box<Double> are not subtypes of Box<Number>
0 голосов
/ 14 ноября 2011

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

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

...