关于java:如何填写List<?

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

我有这些简单的课程:

1
2
3
4
5
6
7
8
9
10
11
12
13
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) { ... }
}

这些类可以绘制在画布上:

1
2
3
4
5
public class Canvas {
    public void draw(Shape s) {
        s.draw(this);
    }
}

我希望将所有圆形和矩形对象放在一个列表中,并在一个迭代语句中绘制所有对象,如下所示:

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

一切都在编译。

如果我创建一个测试类并尝试创建这样的列表,问题就开始了:

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
    }
}

如代码中所述,我不能向列表中添加圆形和矩形对象。

问题:我应该如何修改代码,以便构造

1
List<? extends Shape>

下一步迭代该列表以绘制形状。

事先谢谢。

文章编辑:谢谢!这是一个相当大的突破。本该把这归功于航天卡车司机和他关键的PECS链接,但这是不可能的。出于某种原因,我告诉自己应该使用扩展,从那以后再也不会质疑这个假设。


尝试指定List类型

1
2
3
4
5
6
List<Shape> list = new ArrayList<Shape>();
Shape circle = new Circle();
Rectangle rectangle = new Rectangle();
list.add(circle);
list.add(rectangle);
canvas.drawAll(list);


如果您只需要一个形状列表,就不需要任何通配符。

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

工作很好。

如果你使用List,这意味着列表要么是List要么是List,并且你不能在其中添加任何内容,因为实际类型未知。但是,以下内容可以编译并正常工作:

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

你不知道foo的实际类型,但你知道你可以从那里得到一个Shape

阅读评论中关于PECS原则的链接,它应该把事情弄清楚一点。


因为圆和矩形都是从形状延伸出来的,所以您可以做一个列表并添加这两个对象。

1
2
3
4
5
List<Shape> list = new ArrayList<>();
Circle circle = new Circle();
Rectangle rectangle = new Rectangle();
list.add(circle);
list.add(rectangle);

做这个,你可以使用你的形状的所有方法。如果要了解对象是圆形还是矩形以执行非形状方法,可以执行以下操作:

1
2
3
4
5
6
7
8
9
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()
    }

}