How to fill List<? extends Shape> with derived Circle and Rectangle objects?

孤人 提交于 2019-12-10 23:55:29

问题


I have these simple classes:

public abstract class Shape {
    public abstract void draw(Canvas c);
}

public class Circle extends Shape {
    private int x, y, radius;
    public void draw(Canvas c) { ... }
}

public class Rectangle extends Shape {
    private int x, y, width, height;
    public void draw(Canvas c) { ... }
}

These classes can be drawn on a canvas:

public class Canvas {
    public void draw(Shape s) {
        s.draw(this);
    }
}

I would like to put all Circle and Rectangle objects in a single List and draw all of them in a single iteration statement, like this:

public void drawAll(List<? extends Shape> shapes) {
    for (Shape s : shapes) {
        s.draw(this);
    }
}

Everything compiles.

The problem begins if I make a test class and try to create a list like this:

public class Main {

    public static void main(String[] args) {

        Canvas canvas = new Canvas();

        List<? extends Shape> list = new ArrayList<>();
        Circle circle = new Circle();
        Rectangle rectangle = new Rectangle();
        list.add(circle); // The method add(capture#1-of ? extends Shape) in the type List<capture#1-of ? extends Shape> is not applicable for the arguments (Circle)
        canvas.drawAll(list);
    }
}

As is documented in the code, I cannot add Circle and Rectangle objects to the List.

Question: how should I modify the code such, that I can construct a

List<? extends Shape> 

and next iterate over that List to draw the shapes.

thanks in advance.

Post Edit: Thanks! That was quite a breakthrough. Should have given the credits to SpaceTrucker and his crucial PECS link, but that wasn't possible. For some reason I had told myself that I should use extends and never questioned that assumption since.


回答1:


Try to specify List type

List<Shape> list = new ArrayList<Shape>();
Shape circle = new Circle();
Rectangle rectangle = new Rectangle();
list.add(circle);
list.add(rectangle);
canvas.drawAll(list);



回答2:


Since both circle and rectangle extend from Shape, you can do a List and add both objects.

List<Shape> list = new ArrayList<>();
Circle circle = new Circle();
Rectangle rectangle = new Rectangle();
list.add(circle);
list.add(rectangle);

Doing this, you can use all your Shape's methods. If you want to know if an object is Circle or Rectangle in order to do a non-shape method, you can do:

for(Shape shape : list){
    if(shape instanceof Circle){
        //do stuff casting object : ((Circle)shape).method()
    }
    else if(shape instanceof Rectangle){
        //do stuff casting object : ((Rectangle)shape).method()
    }

}



回答3:


If you just want a list of shapes, you don't need any wildcards.

List<Shape> foo = new ArrayList<>();
foo.add(new Circle());
foo.add(new Rectangle());

works just fine.

If you were to use List<? extends Shape> it would mean that the list is either a List<Circle> or List<Rectangle>, and you can't add anything there since the actual type isn't known. However the following would compile and work just fine:

List<? extends Shape> foo = null;
foo = new ArrayList<Circle>();
foo = new ArrayList<Rectangle>();
foo = new ArrayList<Shape>();

you don't know the actual type of foo, but you know that you can get a Shape out from there.

Read the link in the comment for the PECS principle and it should clear things up a bit.



来源:https://stackoverflow.com/questions/43654936/how-to-fill-list-extends-shape-with-derived-circle-and-rectangle-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!