Java 为什么这种通用赋值是非法的?
我有一门课:Java 为什么这种通用赋值是非法的?,java,generics,bounded-wildcard,Java,Generics,Bounded Wildcard,我有一门课: class Generic<T> { List<List<T>> getList() { return null; } } 这对我来说似乎很奇怪,因为根据Generic的声明,当调用getList时,创建Generic并获取列表是很自然的 事实上,我需要这样写作业: List<? extends List<? extends Number>> list = tt.getList(); //
class Generic<T> {
List<List<T>> getList() {
return null;
}
}
这对我来说似乎很奇怪,因为根据Generic
的声明,当调用getList
时,创建Generic
并获取列表是很自然的
事实上,我需要这样写作业:
List<? extends List<? extends Number>> list = tt.getList(); // this one is correct
List关于您遇到的通配符类型,这是一件棘手但有趣的事情!这是很棘手的,但当你理解它时,它确实是合乎逻辑的
该错误与以下事实有关:通配符?扩展编号
不是指单个具体类型,而是指某个未知类型。因此出现了两次?扩展编号不一定引用同一类型,因此编译器不允许赋值
详细说明
赋值的右侧,tt.getList()
,没有得到类型列表当询问您可能要发布的错误时,即确切的消息,理想情况下是堆栈跟踪。这不是运行时异常,只是编译错误。编译错误说明了什么?阅读通配符,事实上,我知道错误消息的意思,我只是想知道为什么编译器认为这个分配是非法的。换句话说,如果它是合法的,会出什么问题呢?就为了我对它感兴趣:你能声明var list=tt.getList()
获取列表
,或者它不适用于泛型?你是说列表
是的子类型吗List@haoyuwang:是的,没错!很抱歉,我犯了一个错误,will fix。@DorianGray:我相信这就像你说的,你可以使用var
来获取一个与捕获类型完全相同的变量。但是我认为你无论如何不能用那种类型做太多…@Lii你能举例说明如果第一次转让是合法的,会发生什么情况吗。只要有助于理解问题,就不必涉及我的案例。(我的情况很糟)。我将不胜感激。
List<? extends List<? extends Number>> list = tt.getList(); // this one is correct
class Generic<T> {
private List<List<T>> list = new ArrayList<>();
public List<List<T>> getList() {
return list;
}
}
// Start with a concrete type, which will get corrupted later on
Generic<Integer> genInt = new Generic<>();
// Add a List<Integer> to genInt.list. This is not necessary for the
// main example but migh make things a little clearer.
List<Integer> ints = List.of(1);
genInt.getList().add(ints);
// Assign to a wildcard type as in the question
Generic<? extends Number> genWild = genInt;
// The illegal assignment. This doesn't compile normally, but we force it
// using an unchecked cast to see what would happen IF it did compile.
List<List<? extends Number>> list =
(List<List<? extends Number>>) (Object) genWild.getList();
// This is the crucial step:
// It is legal to add a List<Float> to List<List<? extends Number>>.
// list refers to genInt.list, which has type List<List<Integer>>.
// Heap pollution occurs!
List<Float> floats = List.of(1.0f);
list.add(floats);
// notInts in reality is the same list as floats!
List<Integer> notInts = genInt.getList().get(1);
// This statement reads a Float from a List<Integer>. A ClassCastException
// is thrown. The compiler must not allow us to end up here without any
// previous type errors or unchecked cast warnings.
Integer i = notInts.get(0);
List<? extends List<? extends Number>> list = tt.getList();