import java.util.ArrayList;
import java.util.List;
public class App {
class A {
}
class B extends A {
}
class C extends B {
}
class D extends C {
}
public static void main(String[] args) {
List<A> al = new ArrayList<A>();
// 无法修改泛型继承关系
al = new ArrayList<B>(); // 编译错误
al.add(new A());
al.add(new B());
al.add(new C());
A a = al.get(0);
// 声明 List<? extends A> , 实现可能是 继承 A 的任意类型
List<? extends A> al1 = new ArrayList<A>() {
{
// 放入子类
add(new B());
}
};
al1 = new ArrayList<B>() {
{
// 放入子类
add(new C());
}
};
al1 = new ArrayList<C>() {
{
// 无法放入 B
add(new B()); // 编译错误
// 放入子类
add(new D());
}
};
// 虽然编译器知道放入数据一定是继承 A
// List<? extends A> al1 实现类一定是 List<A> 或 List<A 的子类>
// 但是用户指定的实现不确定 比如 ArrayList<C> 无法放入 B 类型,会有类型转换错误
al1.add(new A()); // 编译错误
al1.add(new B()); // 编译错误
// 因为声明的 List<? extends A>, 编译器确定类型一定是 A
A x = al1.get(0);
// 声明 List<? super D> , 实现可能是 D 的任意父类, 兼容放入 D 以及子类
List<? super D> bl1 = new ArrayList<Object>() {
{
// 我放入和 D 类型无关的数据
add("");
add(new D());
}
};
bl1 = new ArrayList<A>() {
{
add(new A());
add(new D());
}
};
// 编译器知道实现一定是 D 的父类
// 支持放入任意 D 和 所有继承 D 的类
// List<? super D> 声明了编译器只能放入 D 和 D 的实现类型
bl1.add(new A()); // 编译失败
bl1.add(new D());
// 编译器无法获取确定实现类支持的数据类型,
// 因为 List<? super D> bl1 可以是 List<D> 或 List<D 的父类> 的实现装载数据
// 如果获取类型转换为 D 会有类型转换错误
D b = bl1.get(0); // 编译错误
Object o = bl1.get(0); // 所有类型的父类是 Object 所以支持
// 需要人为强制转换, 有类型转换异常风险
D b1 = (D) bl1.get(0);
}
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.