The rule for whether a compilation error is raised here is given by 5.5.1:
Given a compile-time reference type S (source) and a compile-time reference type T (target), a casting conversion exists from S to T if no compile-time errors occur due to the following rules.
If S is a class type:
- If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs.
This means it's a valid cast if either type is a subclass of the other. It works this way so that we can do stuff like this:
A actuallyB = new B(); // note implicit widening but could be (A)new B()
B theB = (B)actuallyB;
It's simple for a human to discern that the expression (B)new A()
will throw at run time; however there is no requirement for the compiler to make this discernment.