Type checking is always done at compile time as far as possible.
When you say "(B)a", it is determined at compile time that this
may be legal. After all, B is a subclass of A, so "a" may very well refer to an instance of B. If the compiler were intelligent enough (i.e. with data-flow analysis) it could have seen that "a" does not, in fact, contain a B, but this is not required.
However, because "a" may very well
not refer to an instance of B, the compiler requires you to show that you know what you're doing using the cast operator (B). The conversion is a so-called narrowing conversion. The other way around, in "a = (A)b", you may omit the cast; this is a widening conversion that can never lead to a ClassCastException. Any instance of B is also a valid instance of A.
On the other hand, when you say "(C)b" there is no way that "b" can refer to an instance of C. That's why it is flagged up as a compile-time error.
In summary, there are three possible cases:
- Widening conversions which are always valid; they are performed implicitly when required.
- Narrowing conversions, the validity of which cannot be determined at compile time; they require an explicit cast and may throw a run-time ClassCastException.
- Conversions between incompatible types. These are flagged up as compile-time errors.
HTH
- Peter
[This message has been edited by Peter den Haan (edited October 27, 2001).]