Reputation: 5541
package practice;
class Node<T> {
T data;
public Node(T data) { this.data = data; }
public void setData(T data) {
System.out.println("Node.setData");
this.data = data;
}
}
class MyNode extends Node<Integer> {
public MyNode(Integer data) { super(data); }
@Override
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}
public class Practice {
public static void main(String[] s)
{
MyNode mn = new MyNode(5);
Node n = mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello"); // Causes a ClassCastException to be thrown.
Integer x = mn.data;
}
}
Why does this code throw exception at n.setData("Hello");
when actually it should throw the exception at Integer x = mn.data;
?
http://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html
Upvotes: 2
Views: 356
Reputation: 15250
I think there is a small mistake in the tutorial: they should have said that the error is thrown at line n.setData("Hello");
That's because when you call n.setData("Hello");
you call the bridge method: n.setData(Object object)
on MyNode
class, otherwise you would have a compile time error.
But the bridge method looks like this:
// Bridge method generated by the compiler
//
public void setData(Object data) {
setData((Integer) data);
}
You see that the bridge tries to invoke the setData(Integer anInt)
with a cast on the data
. And this cast fails because you provided a String
.
What's also interesting at this example is that you get no compile time error when using @Override
annotation even that you technically don't override, but the compiler overrides later. The annotation is very very useful here to inform that the setData(Object object)
will be called on MyNode
not on Node
. This explains why you don't see any of the System.out
messages.
Upvotes: 1
Reputation: 15129
Because the type of n
is actually Integer
, which it received from mn
.
It's the same principle as List list = new ArrayList();
The list here is actually an ArrayList
, but only referenced using the List interface. Similarly, even though n
is a Node
, it's implementation is a MyNode
which only accepts Integer
. That's why you can put a String
in setData()
After reading the edit example
The page says that a bridge method is created as follows :
class MyNode extends Node {
// Bridge method generated by the compiler
//
public void setData(Object data) {
setData((Integer) data);
}
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
// ...
}
The bridge method does the following
public void setData(Object data) {
setData((Integer) data);
}
Here it is trying to cast data which is the String
"Hello" into an Integer
. Hence the error is thrown.
Upvotes: 0
Reputation: 159864
You have already defined the type T
for Node
by calling
MyNode mn = new MyNode(5);
namely Integer
type. By calling n.setData("Hello");
you are attempting to pass in a String variable for an Integer field. Node n
is merely a reference for the Integer
typed Node mn
.
Upvotes: 1
Reputation: 605
Because you are trying to set String value to Integer variable.
Upvotes: 2