Both exception and no exception are permissible behaviors. Basically, this goes down to how the compiler erases the statements, whether it is to something like this without casts:
System.out.println(new MyClass().n);
System.out.println(new MyClass().n.getClass());
or to something like this with casts:
System.out.println((Long)new MyClass().n);
System.out.println(((Long)new MyClass().n).getClass());
or one for one statement and one for the other. Both versions are valid Java code that will compile. The question is whether it is permissible for the compiler to compile to one version, or the other, or both.
It is permissible to insert a cast here because that is usually what happens when you take something from a generic context where the type is a type variable, and return it into a context where the type variable takes on a specific type. For example, you could assign new MyClass<Long>().n
into a variable of type Long
without any casts, or pass new MyClass<Long>().n
into a place that expects Long
without any casts, both cases of which obviously will require the compiler to insert a cast. The compiler can just decide to always insert a cast when you have new MyClass<Long>().n
, and it's not wrong to do so, as the expression is supposed to have type Long
.
On the other hand, it is also permissible to not have a cast in these two statements, because in both cases the expression is used in a context where any Object
can be used, so no cast is needed to make it compile and be type safe. Furthermore, in both statements, a cast or no cast would make no difference in behavior if the value was indeed a Long
. In the first statement, it is passed to the version of .println()
that takes Object
, and there is no more specific overload of println
that takes Long
or Number
or anything like that, so the same overload will be chosen regardless of whether the argument is considered as Long
or Object
. For the second statement, .getClass()
is provided by Object
, so it is available regardless of whether the thing on the left is a Long
or Object
. Since the erased code is valid both with and without the cast and the behavior would be the same with and without the cast (assuming the thing is indeed a Long
), the compiler could choose to optimize the cast out.
A compiler could even have a cast in one case and not in the other, perhaps because it only optimizes out the cast in certain simple cases, but doesn't bother to perform analysis in more complicated cases. We don't need to dwell on why a particular compiler decided to compile to one form or another for a particular statement, because both are permissible, and you should not rely on it to work one way or the other.