12

Obviously, this results in a compilation error because Chair is not related to Cat:

class Chair {}
class Cat {}

class Test {
   public static void main(String[] args) {
       Chair chair = new Char(); Cat cat = new Cat();
       chair = (Chair)cat; //compile error
   }
}

Why is it then that I only get an exception at run time when I cast a Cat reference to the unrelated interface Furniture, while the compiler can obviously tell that Cat does not implement Furniture?

interface Furniture {}

class Test {
   public static void main(String[] args) {
       Furniture f; Cat cat = new Cat();
       f = (Furniture)cat; //runtime error
   }
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
enp4yne
  • 638
  • 5
  • 21
  • because polymorphism happens at run time. – Juned Ahsan Oct 02 '13 at 16:12
  • but the compiler knows that Cat doesn't implement Furniture, and that can't change at run time? I might be missing a simple point, but your answer doesn't really help me – enp4yne Oct 02 '13 at 16:16
  • Because. Even though Cat may not directly implement Furniture, some superclass of Cat may. And the compiler chooses to not dig into such ugly details, since the rules for interfaces are pretty convoluted. (Thank you, Sun.) And there is no general rule *requiring* the compiler to detect an inevitable runtime exception (such as divide by zero) -- it's more of a "service" it provides. – Hot Licks Oct 02 '13 at 16:23
  • possible duplicate of [Why does this instanceof code work and does not cause a compile time error?](http://stackoverflow.com/questions/3897467/why-does-this-instanceof-code-work-and-does-not-cause-a-compile-time-error) – Hot Licks Oct 02 '13 at 16:32

1 Answers1

18

The reason this compiles

interface Furniture {}

class Test {
   public static void main(String[] args) {
       Furniture f; 
       Cat cat = new Cat();
       f = (Furniture)cat; //runtime error
   }
}

is that you may very well have

public class CatFurniture extends Cat implements Furniture {}

If you create a CatFurniture instance, you can assign it to Cat cat and that instance can be casted to Furniture. In other words, it's possible that some Cat subtype does implement the Furniture interface.

In your first example

class Test {
    public static void main(String[] args) {
        Chair chair = new Chair();
        Cat cat = new Cat();
        chair = (Chair)cat; //compile error
    }
}

it's impossible that some Cat subtype extends Chair unless Cat itself extends from Chair.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • 7
    It's useful to note that if `Cat` were declared `final`, the compiler would indeed complain (it would know that no subclass of `Cat` could implement `Furniture` since there could be no subclass of `Cat`). – Ted Hopp Oct 02 '13 at 16:53