Question

When I run the source code below, the runtime error that I see in the shell window is as follows:

Exception in thread "main" java.lang.ClassCastException: pkgs.main.A cannot be c
ast to pkgs.test.B
        at pkgs.main.Main.main(Main.java:9)

Should this error be caught by the compiler at compile time, and not at runtime? Here are my three seperate source code files, which collectively compile OK, without errors or warnings:

// ------------------------
// class Main, package main
// ------------------------
package pkgs.main;
import pkgs.test.B;

class Main {
    static public void main(String args[]) {
    ((B)new A()).m();  // causes runtime ClassCastException to be raised.
    }
}


// ---------------------
// class A, package main
// ---------------------
package pkgs.main;

public class A {
    public int m() { return 1; }
}


// ---------------------
// class B, package test  <--- note the different package to classes A and Main
// ---------------------
package pkgs.test;
import pkgs.main.A;

public class B extends A {
    public int m() { return 100; }
}

Here are the contents of my shell-based compile and run batch files:

REM batch file for compilation
javac -Xlint -sourcepath ..\src -d ..\cls ..\src\pkgs\main\Main.java

REM batch file for execution
java -cp ..\cls pkgs.main.Main

This very simple test project is available for a quick download and test at the following DropBox link: https://www.dropbox.com/s/60qi0vbadc5m7es/t16_mk2.7z

Was it helpful?

Solution

The rule for whether a compilation error is raised here is given by 5.5.1:

Given a compile-time reference type S (source) and a compile-time reference type T (target), a casting conversion exists from S to T if no compile-time errors occur due to the following rules.

If S is a class type:

  • If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs.

This means it's a valid cast if either type is a subclass of the other. It works this way so that we can do stuff like this:

A actuallyB = new B(); // note implicit widening but could be (A)new B()
B theB = (B)actuallyB;

It's simple for a human to discern that the expression (B)new A() will throw at run time; however there is no requirement for the compiler to make this discernment.

OTHER TIPS

B is a subclass of A. So An instance of A cannot be cast to B. The reverse is possible.

B b = new B();
A a = (A)b; //valid

A a = new A();
B b = (B)a; //invalid

You may want to read IS A relationship.

Should this error be caught by the compiler at compile time, and not at runtime?

It should be caught at runtime.

Why?

On class Hirearchy class B extends A, consider following code:

void perforAction(A obj) {
    obj.someMethodDeclaredInA();
    //more method calls from A
    if (obj instanceof B) {
        B casted = (B) obj;
        casted.someMethodDeclaredInB();
    }
}

The idea is, that the first part of this method processes objects of A and B alike, and the second part performs some extra action for object from B. Howerver, you have to cast A to B to achieve this, so this cannot be a compile error, because then this kind of code wouldt compile.

You are trying to cast an actual object of A (which is parent) into object reference of B(which is child). So it is giving error.

Had it been actual object of B; but references as object of A; then type casting would have been successful. e.g.

B obj_of_B = new B();
A obj_of_A = obj_of_B;
B other_obj_of_B = (B)obj_of_A;

This would work correctly as though object reference named "obj_of_A" is of type A, actual object is of type B.

So understand the difference between "type of object reference" and "type of actual object". Only at runtime you will know "type of actual object". So this error will be thrown at runtime.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top