I have this class:
class MyClass<N extends Number> {
N n = (N) (new Integer(8));
}
And I want to get these outputs:
System.out.println(new MyClass<Long>().n);
System.out.println(new MyClass<Long>().n.getClass());
Output of first
System.out.println()
statement:8
Output of second
System.out.println()
statement:java.lang.ClassCastException: java.lang.Integer (in module: java.base) cannot be cast to java.lang.Long (in module: java.base)
Why do I get the first output? Isn't there a cast as well? Why do I get the exception in the second output?
PS: I use Java 9; I tried it with the JShell and I got an exception on both outputs. Then I tried it with IntelliJ IDE and got the first output but the exception at the second.
The behavior that IntelliJ shows is clear to me:
You have an unchecked cast in
MyClass
. This meansnew Integer(8)
is not immediately cast toLong
but to the erasureNumber
(which works), when this line is executed:N n =(N)(new Integer(8));
Now let's look at the output statements:
boils down to
String.valueOf(new MyClass<Long>().n)
->((Object)new MyClass<Long>().n).toString()
which works fine, because n is accessed throughObject
and also thetoString()
method is accessed through static typeObject
-> no cast toLong
occurs.new MyClass<Long>().n.toString()
would fail with an exception, becausetoString()
is tried to be accessed via static typeLong
. Therefore a cast of n to typeLong
occurs which is not possible(Integer
can't be cast toLong
).The same thing occurs when executing the 2nd statement:
The
getClass
method (declared inObject
) of typeLong
is tried to be accessed through static typeLong
. Therefore a cast of n to typeLong
occurs which yields a cast exception.JShell behavior:
I tried to reproduce the resulting exception for the first output statement on JShell - Java 9 early access Build 151:
But it seems that JShell gives the exact same results as IntelliJ.
System.out.println(new MyClass<Long>().n);
outputs 8 - no exception.