Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting and Inheritance in Java

Consider this simple code:

class A {}

class B extends A {}

public class TestClass {
    public static void main(String args[]) {
        A[] a, a1;
        B[] b;
        a = new A[10];
        a1 = a;
        b = new B[20];
        a = b; // 1
        b = (B[]) a; // 2
        b = (B[]) a1; // 3
    }
}

Look closely at lines which I commented 1,2 and 3. The line 1 will be allowed during compilation, since assignment is done from a subclass reference to a superclass reference.

The cast in line 2 is needed because a superclass reference is assigned to a subclass reference variable. And this works at runtime because the object referenced to by a is actually of an array of B (line 1).

Now, here's where lies my confusion: line 3 will throw a java.lang.ClassCastException. Now, this means that during runtime, the program realizes that the actual object is not an array of B but is an array of A.

This is exactly what I don't understand. Doesn't B extends A? So it satisfies the condition B IS-A A, correct? And therefore, shouldn't line 3 not throw any exception during run time?

like image 803
Jesse James Avatar asked Jan 05 '23 15:01

Jesse James


2 Answers

a1 is an array of A elements. Since B extends A, all instances of B are also instances of A, but not all instances of A are instances of B. You could define a class C that also extends A and assign instances of that class to the a1 array. Such instances are not instances of B.

Therefore you can't cast an array of A elements to an array of B elements.

like image 107
Eran Avatar answered Jan 12 '23 09:01

Eran


You forgot, that arrays are classes by themselves, and they have their own cast and assignment rules.

Consider this:

    A[] aa = new A[0];
    B[] bb = new B[0];

    System.out.println(aa.getClass());
    System.out.println(bb.getClass());

    System.out.println(aa.getClass().isAssignableFrom(bb.getClass()));
    System.out.println(bb.getClass().isAssignableFrom(aa.getClass()));

Output:

class [Lstuff.small.Try47$A;
class [Lstuff.small.Try47$B;
true
false

Thus, an A[] variable can indeed be assigned a B[], but not the other way around.

like image 32
mtj Avatar answered Jan 12 '23 08:01

mtj