SouR Graphics SouR Graphics - 4 months ago 17
Java Question

Casting object arrays in varargs

Following the Oracle's tutorial on interfaces, I experimented with the code and added a moveAll method which moves all the rectangles(as a varargs) to the position parsed.

public static void moveAll(int x, int y, Relatable... obj) {
Rectangle[] rects = (Rectangle[])obj;
for(Rectangle r: rects){
r.move(x, y);
}
}

public interface Relatable {
public static void moveAll( int x, int y, Relatable... obj) {}
}


Upon compilation I get:

Exception in thread "main" java.lang.ClassCastException: [Linterfaces.Relatable; cannot be cast to [Linterfaces.RectanglePlus;
at interfaces.RectanglePlus.moveAll(RectanglePlus.java:52)
at interfaces.Main.main(Main.java:9)

Answer

Assuming that Rectangle class implements Relatable interface and that Rectangle class has move(int x, int y) method, you get ClassCastException because you cannot treat an array of Relatable as an array of Rectangle even though Rectangle implements an Relatable. Java arrays are covariant, that means it is allowed to do stuff like that:

public class A {...}
public class B extends A{...}
A[] array = new B[2];

regardless of the fact that B[] is not subclass of A[]. Both Relatable[] and Rectangle[] derive directly from Object (as any other array types), so there is no parent - child relationship between them.

As far as your example is concerned, here are a few different approaches to solve this problem:

1. You can cast every element on it's own

public static void moveAll( int x, int y, Relatable... obj) {

    for(Relatable r: obj){
        ((Rectangle)r).move(x, y);
    }

}

2. You can improve the code above using polymorphism. To do that you have to declare move method in Relatable interface. We can reject casting now because because every class that implements Relatable is obliged to implement move(int x,int y) method (otherwise we would have got java.lang.UnsupportedOperationException)

public interface Relatable {
    public static void moveAll( int x, int y, Relatable... obj) {

        for(Relatable r: obj){
            r.move(x, y);
        }

    }

    public void move(int x, int y);

}

Hope this help :)