Java inheritance casting runtime error vs compiler error

The Problem

Consider the code below. B inherits from A, and none of them inherit from String.

I’d like to know the answers to the following questions:

  1. why does the first first cast, B b1 = (B) a1;, produce a runtime error?
  2. why does the first second cast, String b1 = (String) a1;, produce a compilation error?
  3. Why is there a difference? Why doesn’t the compiler see the problem in the first case?

The Code

public class Main {
    public static void main(String[] args) {
        A a1 = new A();
        B b1 = (B) a1;
        String b1 = (String) a1;


with class A:

public class A {}

and class B:

public class B extends A {}


A variable of type A could have been assigned an instance of B, because a B is an A. Eg a Dog is an Animal, so a box labelled “Animal” could contain a dog.

But a variable of type A cannot have been assigned a String. Eg A box labelled “Animal” will not contain a Brick.

You may be asking yourself why the compiler doesn’t complain when we can see that the code will clearly fail – there’s no way the variable is a B; it’s an A!

The compiler looks only at the type of the variable when making its checks. It doesn’t examine what code came before. Although your example is simple, checking what a variable actually contains would be an impossible task in the general case.

Source: stackoverflow