ClassCastException vs. "cannot cast" compilation error

Solution 1:

Why does the code above compile at all? Phone seems unrelated to Roamable to me?

yes because Roamable is an interface it might cause a Run-time exception but not compile time exception, because even if Phone doesn't implement Roamable, a subclass of Phone might, hence the compiler has no way to know it but at the Run time.

It is already defined in java language specification. Check out my answer here.

Why does the code compile with new Phone(), but doesn't it compile with new String()?

Because class String is declared as public final class in java.lang package. As specified in jls 8.1.1.2 final class section: a class declared as final can't be extended and hence it won't have any subclass. So, the compiler already knows that String can't be extended: hence no subclass's existence is possible to implement interface Roamable

Edit: (With response to your below comment)

Let us assume that B is a subclass of A which implements an interface T.

Now an statement :

   T t = (T)new A();

is essentially same as:

   A aObj = new A() ;
   T t = (T)aObj ; // a run-time exception happen

before running into conclusion, let us do the same thing with an object of B:

   A aObj = new B();
   T t = (T)aObj; // no exception happen.

so, the real reason with super class and sub class here is the reference. The aObj class in this second code example is also an instance of class A but it is also an instance of class B which has implemented T.

Solution 2:

String is final so there is no way it can be cast to a Roamable.

Solution 3:

The code compiles because the compiler lets you cast to anything. It is an explicit action by the programmer, and the compiler assumes you have assessed the risks and taken the appropriate precautions.

String is not an instance of Roamable, so you cannot assign an instance of String to a Roamable reference. And that can be determined at compile time, so it fails.