2014-08-27 4 views
3

У меня есть этот код из книги Мышление в Java, где Брюс указывает предупреждение о вызове метода set(). Код выглядит следующим образом:
Родовой тип Erasure Warning

package testPackage; 

    class GenericBase<T> { 
    private T element; 
    public void set(T arg) { arg = element; } 
    public T get() { return element; } 
    } 
    class Derived1<T> extends GenericBase<T> {} 
    class Derived2 extends GenericBase {} // No warning 
    // class Derived3 extends GenericBase<?> {} 
    // Strange error: 
    // unexpected type found : ? 
    // required: class or interface without bounds 
    public class ErasureAndInheritance { 
    @SuppressWarnings("unchecked") 
    public static void main(String[] args) { 
     Derived2 d2 = new Derived2(); 
     Object obj = d2.get(); 
     d2.set(obj); // Warning here! 
     } 
    } 

Если удалить аннотацию, я получаю следующее предупреждение:
Тип безопасности: Набор метод (Object) принадлежит к сырому типу GenericBase. Ссылки на общий тип GenericBase должны быть параметризованы

Вопрос: Почему предупреждение отображается на экране ()? И может кто-нибудь объяснить, что означает это предупреждение?
Btw, я совершенно новичок в Java Generics, и хотя я читал другие вопросы о Generics, я все еще несколько смущен на Erasure.

+0

Erasure => После процесса компиляции код ничего не знает о генериках –

+0

@MarcoAcierno Хорошо, что я понимаю, но мое замешательство происходит из-за смешивания исходного и параметризованного типа. –

ответ

3

Из дока Java here

Дженерик были введены в языке Java, чтобы обеспечить более жесткий тип проверки во время компиляции и поддержка общего программирования. Для реализации дженериков, компилятор Java применяет тип к стиранию:

  • Заменить все параметры типа в родовых типов с их границами или объект, если параметры типа не ограничены. Таким образом, полученный байт-код, , содержит только обычные классы, интерфейсы и методы.
  • Вставьте тип при необходимости, чтобы сохранить безопасность типа.
  • Создание мостовых методов для сохранения полиморфизма в расширенных общих типах.
  • Тип erasure гарантирует, что для параметризованных типов не создаются новые классы; следовательно, дженерики не накладывают на них лишние расходы.

Simple: Каждый родовое является Object после процесса компиляции, он просто добавляет кастинг для вас, и если вы сделали что-то неправильно, он будет генерировать ошибку компилятора.

О unchecked аннотацию, он используется, когда компилятор не может быть уверен, что вы делаете правильно (на самом деле, можно использовать необработанный тип, который то же самое, как GenericBase<Object>)

У вас есть предупреждение, поскольку методы set, за исключением типа T, но поскольку вы используете необработанный тип, он не знает, что такое T, и сгенерируйте это предупреждение, чтобы вы знали, что используете необработанный тип (плохая вещь).

Вы можете использовать аннотации, чтобы сказать: «Я знаю, что это сырой тип, но я знаю, что это законно, и я знаю, что делаю».

Смешивание сырья типы и общие типы возможно благодаря тому, как дженерики реализуются, как я уже сказал выше, после процесса компилятор T становится Object и это означает, что сырье объект как GenericBase это то же самое, как GenericBase<T>.

Причина, по которой он не требует какого-либо литья с помощью дженериков, заключается в том, что он добавит вам приведения (и вы можете быть уверены, что код всегда будет работать во время выполнения, не беспокоясь о возможном ClassCastException).

+0

Одна вещь, которую я хочу прояснить, - это когда вы говорите в последнем абзаце о автоматическом кастинге, вы имеете в виду, что причиной не получения предупреждения о методе get() (из-за возврата T) является автоматическая обработка литья в этом случае? –

+0

В этом случае у вас нет предупреждения, потому что Derived2 содержит объекты, и вы сохраняете его в объекте. Поэтому нет причины генерировать предупреждение, так как никакого каста не требуется вообще –

+0

Если я рассмотрю ваши рассуждения, то и в set(), параметр получения также будет переведен в тип объекта, почему появляется предупреждение? (вы знаете, объект передается при вызове set()) Я имею в виду, что идентификатор типа T переводится в Object везде, где T присутствует правильно? –

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