Учебник Type Erasure на Java

Я читаю общие сведения об Oracle (Type Erasure) и Я не смог понять следующую часть.

Фрагменты кода показаны ниже:

public class Node<T> {

    public T data;

    public Node(T data) { this.data = data; }

    public void setData(T data) {
        System.out.println("Node.setData");
        this.data = data;
    }
}

public class MyNode extends Node<Integer> {
    public MyNode(Integer data) { super(data); }

    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }
}

В следе упоминается следующее:

Рассмотрим следующий код:

MyNode mn = new MyNode(5);
Node n = mn;            // A raw type - compiler throws an unchecked warning
n.setData("Hello");     
Integer x = mn.data;    // Causes a ClassCastException to be thrown.

После стирания типа этот код становится:

MyNode mn = new MyNode(5);
Node n = (MyNode)mn;         // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = (String)mn.data; // Causes a ClassCastException to be thrown.

Цитата из того же учебника -

Вот что происходит при выполнении кода

  • n.setData("Привет"); вызывает выполнение метода setData(Object) для объекта класса MyNode. (Класс MyNode унаследовал setData(Object) от Node.)
  • В теле setData(Object) поле данных объекта, на который ссылается n, присваивается строке.
  • К полю данных того же объекта, на который ссылается mn, можно получить доступ, и ожидается, что оно будет целым числом (поскольку mn — это MyNode, который является Node.
  • Попытка присвоить строку целому числу вызывает исключение ClassCastException из приведения, вставленного при назначении компилятором Java.

Я не могу понять, почему попытка получить данные вызывает исключение. Насколько я понимаю, установка самих данных не должна вызывать исключение (это то, что происходит с моим компилятором, но, поскольку я не использую компилятор Oracle, я не уверен, что правильно)?

Если я правильно понимаю, класс MyNode должен иметь два метода:

void setData(Object); //bridge method
void setData(Integer);

Таким образом, вызов setData(Object) на узле должен по праву вызывать метод моста в MyNode, который, в свою очередь, вызывает setData(Integer), где должно быть выдано исключение приведения класса. Но учебник Oracle изо всех сил пытается сказать, что это не так. Так что не так с моим пониманием? Пожалуйста, помогите мне понять.


person MSS    schedule 13.03.2016    source источник
comment
Да, похоже, что учебник неправильный. setData должен выдать ошибку времени выполнения.   -  person Dima    schedule 13.03.2016


Ответы (2)


Если я правильно понимаю, класс MyNode должен иметь два метода
void setData(Object); //метод моста
void setData(Integer);

Это правда. Класс MyNode будет иметь выше двух методов.

Выполнение javap на MyNode.class также показывает это. См. оба метода ниже, выделенные между **

javap MyNode.class
Compiled from "MyNode.java"  
public class com.demo.generics.demo.MyNode extends com.demo.generics.demo.Node<j
ava.lang.Integer> {
  public com.demo.generics.demo.MyNode(java.lang.Integer);
  **public void setData(java.lang.Integer);**
  public static void main(java.lang.String[]);
  **public void setData(java.lang.Object);**
}

Таким образом, вызов setData(Object) на узле должен по праву вызывать метод моста в MyNode, который, в свою очередь, вызывает setData(Integer), где должно быть выдано исключение приведения класса.

Это также верно. Вызов этого приводит к следующему исключению:

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at com.demo.generics.demo.MyNode.setData(MyNode.java:1)
    at com.demo.generics.demo.MyNode.main(MyNode.java:14)

MyNode.java:14 я звоню n.setData("Hello");

это то, что происходит с моим компилятором, но, поскольку я не использую компилятор Oracle, я не уверен, что правильно)?

Это не зависит от компилятора, оно должно быть одинаковым.

person Madhusudana Reddy Sunnapu    schedule 13.03.2016
comment
Значит, учебник неправильный? Я думаю, их просто нужно проинформировать, чтобы они могли обновить свой учебник. Кстати, вы используете компилятор Oracle? - person MSS; 13.03.2016
comment
@AshishDaggubatti Я просмотрю учебник и прокомментирую его. Да, у меня Oracle JDK. - person Madhusudana Reddy Sunnapu; 13.03.2016
comment
@AshishDaggubatti хм... Похоже, учебник вводит в заблуждение относительно того, когда именно будет поднят ClassCastException. Кажется парадоксальным, что одна рука показывает, что ClassCastException будет поднято в заявлении Integer x = mn.data;, а затем в конце говорится, что сгенерированное bridge method вызовет setData((Integer) data);, и в идеале это точка, где действительно поднимается ClassCastException. Если только мы неправильно истолковали туториал, в чем я сомневаюсь :-) - person Madhusudana Reddy Sunnapu; 13.03.2016

Я наткнулся на это вчера, когда читал документацию. Я открыл эту ошибку в средстве отслеживания ошибок Oracle и добавил это вопрос как ссылка.

person Pedro    schedule 21.06.2019