I am reading the Generics trail on Oracle (Type Erasure) and I was not able to understand the following part.
The code snippets are shown below:
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);
}
}
The trail mentions the following:
Consider the following code:
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.
After type erasure, this code becomes:
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.
Quoting from the same tutorial -
Here is what happens as the code is executed
- n.setData("Hello"); causes the method setData(Object) to be executed on the object of class MyNode. (The MyNode class inherited setData(Object) from Node.)
- In the body of setData(Object), the data field of the object referenced by n is assigned to a String.
- The data field of that same object, referenced via mn, can be accessed and is expected to be an integer (since mn is a MyNode which is a Node.
- Trying to assign a String to an Integer causes a ClassCastException from a cast inserted at the assignment by a Java compiler.
I am not able to understand why trying to retrieve the data causes the exception. As far as my understanding goes shouldn't setting the data itself throw an exception (this is what happens on my compiler but since I am not using Oracle's compiler I am not sure which is right)?
If my understanding is right the class MyNode should have two methods :
void setData(Object); //bridge method
void setData(Integer);
So calling setData(Object) on Node should rightfully call the bridge method in MyNode which in turn calls setData(Integer) which is where the class-cast exception should be thrown. But Oracle' tutorial goes out of the way to say that this is not the case. So what is wrong with my understanding? Please help me understand.
That is true. MyNode class will have above two methods.
Doing a
javap
onMyNode.class
reveals it as well. See both the methods below highlighted between **This is true as well. Calling it results in following exception:
MyNode.java:14
is where I am callingn.setData("Hello");
This is not compiler dependent it should be same across.