Max*_*sev 31 java generics java-8
请考虑以下代码示例:
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List list = new ArrayList<Integer>();
String response = getProducer(list).get();
}
static Producer<String> getProducer(List<Integer> list) {
return new Producer<String>();
}
}
class Producer<T> {
T get() {
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
在Java 7中编译时,它只会产生一个预期的警告getProducer(list):
警告:(7,39)java:需要取消选中转换:
java.util.List<java.lang.Integer>找到:java.util.List
但是,在Java 8中编译时,它会为response = getProducer(list).get()赋值生成以下错误:
错误:(7,48)java:不兼容的类型:
java.lang.Object无法转换为java.lang.String
显然,返回的类型getProducer(list)不是Producer<String>,但是被删除Producer(这也通过IDE中的"提取变量"功能来确认).这非常令人费解,因为getProducer方法总会返回Producer<String>.
奇怪的是,它可以通过在调用getProducer方法时避免未经检查的转换来修复,或者通过:
getProducer从List<Integer>到Listlist变量类型更改List为List<Integer>6to*_*ton 17
从第二个链接:
在JDK 7中编译带有警告的以下代码将无法在JDK 8中编译:
import java.util.List;
class SampleClass {
static class Baz<T> {
public static List<Baz<Object>> sampleMethod(Baz<Object> param) {
return null;
}
}
private static void bar(Baz arg) {
Baz element = Baz.sampleMethod(arg).get(0);
}
}
Run Code Online (Sandbox Code Playgroud)
在JDK 8中编译此代码会产生以下错误:
SampleClass.java:12:错误:不兼容的类型:对象无法转换为Baz
Run Code Online (Sandbox Code Playgroud)Baz element = Baz.sampleMethod(arg).get(0);注意:SampleClass.java使用未经检查或不安全的操作.注意:使用-Xlint重新编译:取消选中以获取详细信息.1错误
由此得出,OP的代码可以通过替换这一行来修复(右侧的类型声明让我失望 - 我把它读作一个不是的类型数组列表):
List list = new ArrayList<Integer>();
Run Code Online (Sandbox Code Playgroud)
同
List<Integer> list = new ArrayList<Integer>();
Run Code Online (Sandbox Code Playgroud)
这不会导致从返回类型的方法中删除类型 getProducer(List<Integer> list)
再次引用第二个链接:
在此示例中,将原始类型传递给
sampleMethod(Baz<Object>)可通过子类型应用的 方法(请参阅JLS,Java SE 7 Edition,第15.12.2.2节).未经检查的转换对于适用的方法是必要的,因此其返回类型将被删除(请参阅JLS,Java SE 7 Edition,第15.12.2.6节).在这种情况下,返回类型sampleMethod(Baz<Object>)是java.util.List而不是java.util.List<Baz<Object>>并且因此返回类型get(int)是Object,它与赋值兼容Baz.
Hol*_*ger 13
让我们看看Java语言规范:
15.12.2.6.方法调用类型
...
如果所选方法不是通用的,那么:
- 如果该方法需要未经检查的转换,则调用类型的参数类型是方法类型的参数类型,返回类型和抛出类型由返回类型的删除和方法的抛出类型给出.类型.
...
15.12.2.6.方法结果和引发类型
所选方法的结果类型确定如下:
如果声明所选方法的返回类型为void,则结果为void.
否则,如果该方法需要未经检查的转换,则结果类型是方法声明的返回类型的擦除(第4.6节).
重要的是要理解,"通用方法"的含义是:
8.4.4.通用方法
如果方法声明了一个或多个类型变量(§4.4),则该方法是通用的.
换句话说,该方法
static Producer<String> getProducer(List<Integer> list)
Run Code Online (Sandbox Code Playgroud)
具有泛型参数和返回类型,但不是通用的,因为它不声明类型变量.
因此引用的部分适用,尽管在先决条件方面存在差异,但他们同意这种特定方法调用的后果," 如果该方法需要未经检查的转换,那么结果类型是方法声明的擦除...返回类型 ".
因此,旧的编译器通过使用返回类型Producer<String>而不是擦除来违反规范Producer.
| 归档时间: |
|
| 查看次数: |
6151 次 |
| 最近记录: |