一个)
List<? super Shape> shapeSuper = new ArrayList<Shape>();
shapeSuper.add(new Square()); //extends from SHAP
shapeSuper.add(new DoubleSquare()); //extends from SQ
shapeSuper.add(new TripleSquare()); //extends from DS
shapeSuper.add(new Rectangle()); //extends from SHAP
shapeSuper.add(new Circle()); //extends from SHAP
for (Object object : shapeSuper) { ... }
Run Code Online (Sandbox Code Playgroud)
当我只能添加Shape及其衍生物时,为什么迭代必须是Objects?
B)
List<? super Shape> shapeSuper = new ArrayList<Object>();
shapeSuper.add(new Object()); //compilation error
Run Code Online (Sandbox Code Playgroud)
为什么上面的行会产生编译错误?
Thi*_*ave 26
对于你的例子,你可以使用List<Shape>像丹和保罗所说的平原; 您不需要使用通配符问号语法,例如List<? super Shape>或List<? extends Shape>).我认为您的基本问题可能是"我何时会使用其中一种问号样式声明?" (Julien引用的Get和Put原则是这个问题的一个很好的答案,但我认为除非你在一个例子的上下文中看到它,否则它没有多大意义.)这是我对Get和扩展版本的看法. Put原则何时使用通配符.
使用<? extends T>如果......
Foo<T>readSource使用<? super T>如果......
Foo<T>writeDest这是一个特定示例的演练,演示了通配符背后的思想.想象一下,您正在编写一个processSquare方法,该方法从列表中删除一个正方形,对其进行处理,并将结果存储在输出列表中.这是方法签名:
void processSquare(List<Square> iSqua, List<Square> oSqua)
{ Square s = iSqua.remove(0); s.doSquare(); oSqua.add(s); }
Run Code Online (Sandbox Code Playgroud)
现在,您创建一个DoubleSquares列表,它扩展Square,并尝试处理它们:
List<DoubleSquare> dsqares = ...
List<Square> processed = new ArrayList<Square>;
processSquare(dsqares, processed); // compiler error! dsquares is not List<Square>
Run Code Online (Sandbox Code Playgroud)
编译器因错误而失败,因为dsquares List<DoubleSquare>的类型与processSquare的第一个参数的类型不匹配List<Square>.也许DoubleSquare是一个Square,但是你需要告诉编译器a List<DoubleSquare>is-a List<Square>用于processSquare方法.使用<? extends Square>通配符告诉编译器您的方法可以获取Square的任何子类的List.
void processSquare(List<? extends Square> iSqua, List<Square> oSqua)
Run Code Online (Sandbox Code Playgroud)
接下来,您将改进应用程序以处理Circles和Squares.您希望将所有已处理的形状聚合在一个包含圆形和方形的列表中,因此您将已处理列表的类型从a List<Square>更改为List<Shape>:
List<DoubleSquare> dsqares = ...
List<Circle> circles = ...
List<Shape> processed = new ArrayList<Square>;
processSquare(dsqares, processed); // compiler error! processed is not List<Square>
Run Code Online (Sandbox Code Playgroud)
编译器失败并出现新错误.现在处理列表的类型List<Shape>与processSquare的第二个参数不匹配List<Square>.使用<? super Square>通配符告诉编译器给定参数可以是任何超类 Square 的List .
void processSquare(List<? extends Square> iSqua,
List<? super Square> oSqua)
Run Code Online (Sandbox Code Playgroud)
这是该示例的完整源代码.有时我发现通过一个工作示例开始然后打破它以查看编译器如何反应来更容易学习东西.
package wild;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public abstract class Main {
// In processing the square,
// I'll take for input any type of List that can PRODUCE (read) squares.
// I'll take for output any type of List that can ACCEPT (write) squares.
static void processSquare(List<? extends Square> iSqua, List<? super Square> oSqua)
{ Square s = iSqua.remove(0); s.doSquare(); oSqua.add(s); }
static void processCircle(List<? extends Circle> iCirc, List<? super Circle> oCirc)
{ Circle c = iCirc.remove(0); c.doCircle(); oCirc.add(c); }
public static void main(String[] args) {
// Load some inputs
List<Circle> circles = makeList(new Circle());
List<DoubleSquare> dsqares = makeList(new DoubleSquare());
// Collated storage for completed shapes
List<Shape> processed = new ArrayList<Shape>();
// Process the shapes
processSquare(dsqares, processed);
processCircle(circles, processed);
// Do post-processing
for (Shape s : processed)
s.shapeDone();
}
static class Shape { void shapeDone() { System.out.println("Done with shape."); } }
static class Square extends Shape { void doSquare() { System.out.println("Square!"); } }
static class DoubleSquare extends Square {}
static class Circle extends Shape { void doCircle() { System.out.println("Circle!"); } }
static <T> List<T> makeList(T a) {
List<T> list = new LinkedList<T>(); list.add(a); return list;
}
}
Run Code Online (Sandbox Code Playgroud)
Jul*_*ang 17
第(2.4)节中的"获取和放置原则"是来自Java Generics和Collections的真正的宝石:
获取和放置原则:当您只从结构中获取值时使用扩展通配符,当您仅将值放入结构时使用超级通配符,并且当您同时获取和放置时不使用通配符.

此外,将类型声明List<? super Shape> shapeSuper为一种不良形式,因为它限制了它的使用.通常,我使用通配符的唯一方法是方法签名:
public void foo(List<? super Shape> shapeSuper)
Run Code Online (Sandbox Code Playgroud)
尝试将 shapeSuper 声明为List<Shape>。然后你可以做
for (Shape shape : shapeSuper)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
18258 次 |
| 最近记录: |