The difference is because you don't use the result of the method in the first case, but you do in the second.
A cast is an expression, but it's not a StatementExpression
. This means that you can't write this:
(String) somethingReturningAString();
but you can write:
String aString = (String) somethingReturningAString();
At compile time, the compiler inserts checkcast
instructions where it needs to, and where it can:
- It can't insert a cast for the first case, so no checking takes place.
- It can (and has to) insert a cast in the second case, in order to ensure that it's assigning something that's actually a
String
to a String
variable. As such, it checks the cast, and that fails.
It's worth noting that there are some perhaps unexpected cases where a cast isn't strictly necessary, but is inserted. For example:
Scratch.<String>getSomething(x -> "hello").toString();
would fail with a ClassCastException
, since it would be transformed to:
((String) Scratch.getSomething(x -> "hello")).toString();
even though Object
has a toString()
method, and so it could invoke that without a cast.