Java泛型捕获列表<?>

vik*_*.rk 5 java generics

我正在查看Java Generics文档并找到这段代码,

public class WildcardError {

void foo(List<?> l) {
    //This give a compile time error
    l.set(0,l.get(0));
}
}
Run Code Online (Sandbox Code Playgroud)

我可以理解,我们从a中获取一个元素List<?>并尝试将其设置为另一个元素List<?>.所以编译器会出错.我的问题是,当2个列表不同时,l.set(0, m.get(0))这里列出l并且m不同,这是有道理的.但在上面的例子中,ll列表相同.为什么编译器不够聪明才能看到它?实施起来难吗?

编辑:我知道我可以通过辅助方法或使用T而不是使用?.来修复它.只是想知道为什么编译器不会为我做这件事.

Luk*_*der 9

在您的具体情况下,您可以明确解决此问题:

public class WildcardError {
    <T> void foo(List<T> l) {
        // This will work
        l.set(0, l.get(0));
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您不想更改原始API,请引入委托帮助程序方法:

public class WildcardError {
    void foo(List<?> l) {
        foo0(l);
    }

    private <T> void foo0(List<T> l) {
        // This will work
        l.set(0, l.get(0));
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,编译器无法推断出"明显"的<T>类型.我一直在想这个.这似乎可以在编译器中得到改进,因为每张外卡都可以非正式地转换为未知<T>类型.可能有一些原因可以解释为什么这个被省略,也许这只是直觉,但在形式上是不可能的.

更新:

请注意,我刚看到这种特殊的实现Collections.swap():

public static void swap(List<?> list, int i, int j) {
    final List l = list;
    l.set(i, l.set(j, l.get(i)));
}
Run Code Online (Sandbox Code Playgroud)

JDK家伙采用原始类型,以便在本地处理此问题.这是一个强有力的声明,表明这可能应该由编译器支持,但由于某种原因(例如,没有时间正式指定这一点)只是没有完成


aio*_*obe 4

编译器报告错误,因为一般来说,它无法判断两个表达式(在本例中为ll)是否引用同一个列表。

相关的,有点笼统的问题: