Java 省略<&燃气轮机;非直觉地破坏此代码
我创建了一个MWE,其中通过添加Java 省略<&燃气轮机;非直觉地破坏此代码,java,generics,foreach,Java,Generics,Foreach,我创建了一个MWE,其中通过添加更改单行可以解决编译器错误 以下代码未编译: import java.util.List; public class MainClass { public void traverse() { List<MyEntity> list = null /* ... */; for (MyEntity myEntity : list) { for (String label : myEntit
更改单行可以解决编译器错误
以下代码未编译:
import java.util.List;
public class MainClass {
public void traverse() {
List<MyEntity> list = null /* ... */;
for (MyEntity myEntity : list) {
for (String label : myEntity.getLabels()) { // <-- Offending Line
/* ... */
}
}
}
interface MyEntity<T> {
T get();
List<String> getLabels();
}
}
将有问题的行中的定义从MyEntity MyEntity
更改为MyEntity MyEntity
可以解决此问题。我想知道,除非我将通配符添加到父类中,否则为什么每个对象的返回类型都被视为对象
,而不是字符串
?请注意,getLabels()
本身不包含泛型
根据,使用迭代器将for-each编译为循环。有趣的是,手动将for each扩展为这样一个迭代器是有效的:
Iterator<String> iterator = myEntity.getLabels().iterator();
while (iterator.hasNext()) {
String label = iterator.next();
/* ... */
}
Iterator Iterator=myEntity.getLabels().Iterator();
while(iterator.hasNext()){
字符串标签=迭代器.next();
/* ... */
}
有人能解释一下原因吗?首先,代码示例的方法体可以简化为:
public void traverse() {
MyEntity myEntity = null;
for (String label : myEntity.getLabels()) { // <-- Offending Line
/* ... */
}
}
不可能以部分原始类型(罕见类型)访问内部
类型):
Outer.Inner x=null;//非法的
UPD-2:当我收到关于
Iterator Iterator=myEntity.getLabels().Iterator()的问题时代码>,为什么可以这样做,而第一个示例不起作用
我个人同意这看起来令人困惑。但规则就是这样。本例的JLS段落中也涵盖了该情况:
class Cell<E> {
E value;
Cell(E v) { value = v; }
E get() { return value; }
void set(E v) { value = v; }
public static void main(String[] args) {
Cell x = new Cell<String>("abc");
System.out.println(x.value); // OK, has type Object
System.out.println(x.get()); // OK, has type Object
x.set("def"); // unchecked warning
}
}
类单元{
E值;
单元(EV){value=v;}
E get(){返回值;}
无效集(EV){value=v;}
公共静态void main(字符串[]args){
单元x=新单元(“abc”);
System.out.println(x.value);//好,有类型对象
System.out.println(x.get());//好,有类型对象
x、 set(“def”);//未选中警告
}
}
更仔细地解释为什么Iterator Iterator=myEntity.getLabels().Iterator()代码>JLS的工作基于此规则:
也就是说,Java编程的子类型规则(§4.10.2)
语言使原始类型的变量可以被赋值
任何类型的参数化实例的值
同样,您也可以编写编译良好的代码,如下所示:
List<String> labels = myEntity.getLabels();
for (String label : labels) { // <-- OK, no error here
/* ... */
}
List labels=myEntity.getLabels();
对于(stringlabel:labels){//Nice one,以前从未见过,谢谢!不过我需要一些进一步的澄清:假设,如您所述,将myEntity
声明为raw也会使所有成员都是raw,那么我如何将myEntity.getLabels()的结果存储在(非raw!)中Iterator
?这难道不应该是非法的吗?情况有点不同。Iterator Iterator()
包含类型变量,而不是泛型类型。当您在Iterator Iterator
中指定此类型时,实际上就是“还原”这个类型,这就是为什么它工作的原因,它本身就是原始类型。但是,因为它不是直接指定类型的方法,所以它会给你编译时未检查的警告。list labels=myEntity.getLabels()
那么编译器就可以了。这是因为赋值中允许某种类型的强制吗?@FabienBenoit Koch请看我的更新,也许它可以给你一些帮助clue@Andremoniy“恢复”您的部分评论为我澄清了这一点。因此,感谢您的回答,我了解到声明一个原始类型会使其所有成员都是原始的,甚至是与类本身的类型参数完全不相关的成员。谢谢!!
Outer.Inner<Double> x = null; // illegal
class Cell<E> {
E value;
Cell(E v) { value = v; }
E get() { return value; }
void set(E v) { value = v; }
public static void main(String[] args) {
Cell x = new Cell<String>("abc");
System.out.println(x.value); // OK, has type Object
System.out.println(x.get()); // OK, has type Object
x.set("def"); // unchecked warning
}
}
List<String> labels = myEntity.getLabels();
for (String label : labels) { // <-- OK, no error here
/* ... */
}