如何填写列表<?使用派生的 Circle 和 Rectangle 对象扩展 Shape>?
How to fill List<? extends Shape> with derived Circle and Rectangle objects?
我有这些简单的 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) { ... }
}
这些 classes 可以画在 canvas:
public class Canvas {
public void draw(Shape s) {
s.draw(this);
}
}
我想将所有 Circle 和 Rectangle 对象放在一个 List 中,并在一个迭代语句中绘制所有对象,如下所示:
public void drawAll(List<? extends Shape> shapes) {
for (Shape s : shapes) {
s.draw(this);
}
}
编译一切。
如果我进行测试 class 并尝试创建如下列表,问题就开始了:
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);
}
}
如代码中所述,我无法将 Circle 和 Rectangle 对象添加到列表中。
问题:我应该如何修改代码,以便我可以构造一个
List<? extends Shape>
接下来遍历该列表以绘制形状。
提前致谢。
Post 编辑:谢谢!那是一个很大的突破。应该将功劳归功于 SpaceTrucker 和他至关重要的 PECS link,但这是不可能的。出于某种原因,我告诉自己我应该使用 extends 并且从那以后就再也没有质疑过这个假设。
尝试指定List
类型
List<Shape> list = new ArrayList<Shape>();
Shape circle = new Circle();
Rectangle rectangle = new Rectangle();
list.add(circle);
list.add(rectangle);
canvas.drawAll(list);
由于圆形和矩形都是从 Shape 扩展而来的,因此您可以创建一个 List 并添加这两个对象。
List<Shape> list = new ArrayList<>();
Circle circle = new Circle();
Rectangle rectangle = new Rectangle();
list.add(circle);
list.add(rectangle);
这样,您就可以使用 Shape 的所有方法。如果你想知道一个对象是圆形还是矩形以便执行非形状方法,你可以这样做:
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()
}
}
如果您只需要一个形状列表,则不需要任何通配符。
List<Shape> foo = new ArrayList<>();
foo.add(new Circle());
foo.add(new Rectangle());
工作正常。
如果您要使用 List<? extends Shape>
,则意味着该列表是 List<Circle>
或 List<Rectangle>
,并且您不能在其中添加任何内容,因为实际类型不是'不知道。但是,以下内容可以编译并正常工作:
List<? extends Shape> foo = null;
foo = new ArrayList<Circle>();
foo = new ArrayList<Rectangle>();
foo = new ArrayList<Shape>();
您不知道 foo
的实际类型,但您知道可以从那里得到 Shape
。
阅读评论中的 link PECS 原则,它应该会清楚一点。
我有这些简单的 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) { ... }
}
这些 classes 可以画在 canvas:
public class Canvas {
public void draw(Shape s) {
s.draw(this);
}
}
我想将所有 Circle 和 Rectangle 对象放在一个 List 中,并在一个迭代语句中绘制所有对象,如下所示:
public void drawAll(List<? extends Shape> shapes) {
for (Shape s : shapes) {
s.draw(this);
}
}
编译一切。
如果我进行测试 class 并尝试创建如下列表,问题就开始了:
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);
}
}
如代码中所述,我无法将 Circle 和 Rectangle 对象添加到列表中。
问题:我应该如何修改代码,以便我可以构造一个
List<? extends Shape>
接下来遍历该列表以绘制形状。
提前致谢。
Post 编辑:谢谢!那是一个很大的突破。应该将功劳归功于 SpaceTrucker 和他至关重要的 PECS link,但这是不可能的。出于某种原因,我告诉自己我应该使用 extends 并且从那以后就再也没有质疑过这个假设。
尝试指定List
类型
List<Shape> list = new ArrayList<Shape>();
Shape circle = new Circle();
Rectangle rectangle = new Rectangle();
list.add(circle);
list.add(rectangle);
canvas.drawAll(list);
由于圆形和矩形都是从 Shape 扩展而来的,因此您可以创建一个 List 并添加这两个对象。
List<Shape> list = new ArrayList<>();
Circle circle = new Circle();
Rectangle rectangle = new Rectangle();
list.add(circle);
list.add(rectangle);
这样,您就可以使用 Shape 的所有方法。如果你想知道一个对象是圆形还是矩形以便执行非形状方法,你可以这样做:
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()
}
}
如果您只需要一个形状列表,则不需要任何通配符。
List<Shape> foo = new ArrayList<>();
foo.add(new Circle());
foo.add(new Rectangle());
工作正常。
如果您要使用 List<? extends Shape>
,则意味着该列表是 List<Circle>
或 List<Rectangle>
,并且您不能在其中添加任何内容,因为实际类型不是'不知道。但是,以下内容可以编译并正常工作:
List<? extends Shape> foo = null;
foo = new ArrayList<Circle>();
foo = new ArrayList<Rectangle>();
foo = new ArrayList<Shape>();
您不知道 foo
的实际类型,但您知道可以从那里得到 Shape
。
阅读评论中的 link PECS 原则,它应该会清楚一点。