2014-09-20 4 views
1

Следующий пример взято из Generics FAQ.Подстановочный знак, параметризованный не принимающий объект -why?

public class Box<T> { 
    private T t; 

    public Box(T t) { 
     this.t = t; 
    } 

    public void put(T t) { 
     this.t = t; 
    } 

    public T take() { 
     return t; 
    } 

    public static void main(String[] args) { 
     Box<?> box = new Box<Object>(new Object()); 
     Object o = new Object(); 
     box.put(o); // Compiler error 
     o = box.take(); // ok 
    } 

} 

Если вы посмотрите на декомпилированную версию put() принимает объект. Итак, почему компилятор не принимает Object в put()?

public class Box 
{ 

    public Box(Object t) 
    { 
     this.t = t; 
    } 

    public void put(Object t) 
    { 
     this.t = t; 
    } 

    public Object take() 
    { 
     return t; 
    } 

    public static void main(String args[]) 
    { 
     Box box = new Box(new Object()); 
     Object o = new Object(); 
     o = box.take(); 
    } 

    private Object t; 
} 

ответ

2

Для проверки типов компилятора, Box<?> отличается от Box<Object>. A Box<Object> определенно будет содержать объект, поэтому нормально звонить put(Object). A Box<?> имеет неизвестный параметр типа. Неизвестно отличается от Object.

Это может быть Integer например. Вызов put(Object) на Box<Integer> будет ошибкой. Если компилятор принял это решение, вы можете изменить свою программу на это:

Box<?> box = new Box<Integer>(1); 
Object o = new Object(); 
box.put(o); 

И имеют очень четкое несоответствие типа. Разрешение последней строки для компиляции просто отложило бы ошибку во время выполнения.

Другими словами, стирание общего типа не означает, что компилятор не знает общих типов во время компиляции. Он делает все возможное, чтобы ловить ошибки, прежде чем эта информация будет стерта.

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