Search code examples
javaarraysgenericssuperclass

Bounded wildcards for class and super class array


I have a class Shape and a class Circle that extends Shape as follows:

public class Shape {
  private double area;
  public Shape(double thatArea) {
      this.area = thatArea;
  }

  public double getArea() {
      return this.area;
  }
}

public class Circle extends Shape {
    private double radius;
    public Circle(double radius) {
        super(3.14*radius*radius);
    }

    public double getRadius() {
        return this.radius;
    }
}

Supposed that I create an array of shapes as follows

Shape[] shapes = new Shape[3];
shapes[0] = new Shape(100.0);
shapes[1] = new Circle(5.0);
shapes[2] = new Shape(35.0);

And have a filter by area method like this

public Shape[] filterByMaxArea(double maxArea) {
    ArrayList<Shape> shapeResult = new ArrayList<>();

    for (Shape s : shapes) {
        if (s.getArea < maxArea) shapeResult.add(s);
    }

    return (Shape[]) shapeResult.toArray();
}

If I call the filterByMaxArea() method like this

filterByMaxArea(1000); // in order to include the 
circle too

Then the compiler throws a ClassCastException

Exception in thread "main" java.lang.ClassCastException: java.base/[Ljava.lang.Object; cannot be cast to [Lmypackage.Shape;
at mypackage.Main.filterByMaxArea(Main.java:74)

Where line 74 in the code is this

return (Shape[]) shapeResult.toArray();

Can someone explain me why does the cast fail even though the Circle is a subtype of Shape and previously I had an array of Shape and Circle instances ?

P.S I have tried also declaring the ArrayList with bounded wildcards without any luck.

 ArrayList<? extends Shape> shapeResult = new ArrayList<>();

Solution

  • toArray() returns Object[], there is a overloaded version of toArray(T[] a) which will give the desired result, use it like

    return shapeResult.toArray(new Shape[shapeResult.size()]);