Стирание стилей Java-дженериков

Я хотел бы спросить о правилах стирания типа Java.

Если у нас есть классы:

public class Shape{}
public class Circle extends Shape{}


public class Base<T extends Shape>{
    T x;
    public void setX(T t){}
}

public class MainClass(){
    public static void main(String... _arg){
         Base<? extends Shape> bs = new Base<Circle>(); 
         bs.setX(new Circle()); // <- compilation problem
    }
}

Можете ли вы объяснить мне, почему вызов метода setX() вызывает проблему компиляции?

Ответ 1

Потому что компилятор не знает, что new Circle действителен. Рассмотрим этот код:

Base<? extends Shape> bs = new Base<Square>();  // Really a Base<Square> 
bs.setX(new Circle());

(FYI, очень похожий пример приведен в учебном пособии Java по шаблонам.)

Теперь вы можете воскликнуть: "Но компилятор действительно может видеть это Base<Square>!". Но не в общем. Рассмотрим это:

Base<? extends Shape> bs = someInterface.getBaseOfSomeKindOfShape();
bs.setX(new Circle());