有人可以向我解释为什么明确需要为ForEachLoop实例分配泛型类型?
为什么编译器抱怨:类型不匹配:无法从元素类型Object转换为String?
JDK 1.5.0_09
import java.util.ArrayList;
import java.util.Collection;
public class ForEachLoop<T> {
public static void main(String[] args) {
// Non functional version
ForEachLoop f = new ForEachLoop();
// Functional version
//ForEachLoop<Integer> f = new ForEachLoop();
// Type mismatch: cannot convert from element type Object to String
for(String a : f.getStrings()) {
System.out.println(a);
}
}
public Collection<String> getStrings() {
Collection<String> strings = new ArrayList<String>();
strings.add("Hello");
return strings;
}
}
Run Code Online (Sandbox Code Playgroud)
And*_*anu 10
这是一个相当常见的错误:
ForEachLoop f = new ForEachLoop();
Run Code Online (Sandbox Code Playgroud)
应该
ForEachLoop<Something> f = new ForEachLoop<Something>();
Run Code Online (Sandbox Code Playgroud)
如果您使用原始类型(您不应该使用),编译器将清除该实例的所有通用信息,即使它不是类型参数T,以使其与1.5之前的代码兼容.
如果您正在为Java 1.4或更低版本编写,则只使用原始类型,在这种情况下,您不应该使用任何泛型.在字节码级别,该方法在类型擦除后返回Collection(raw).通常,如果实例具有泛型类型集,当您尝试对get集合执行时,编译器将使用通用信息来确定它应该返回一个String,然后在字节码级别它会自动转换它从中接收的Object Collection to String(因为它保证是一个String).但是如果使用原始类型,编译器将忽略所有通用信息,并且不再为您自动转换对象.
编辑:在原始类型部分中有以下内容:
上述规则的另一个含义是原始类型的泛型内部类本身只能用作原始类型:
Run Code Online (Sandbox Code Playgroud)class Outer<T>{ class Inner<S> { S s; } }无法访问Inner作为部分原始类型("稀有"类型)
Run Code Online (Sandbox Code Playgroud)Outer.Inner<Double> x = null; // illegal Double d = x.s;因为外部本身是原始的,所以它的所有内部类,包括Inner,所以不可能将任何类型的参数传递给它.
原始类型的使用仅允许作为遗留代码兼容性的让步.强烈建议不要在将通用性引入Java编程语言之后编写的代码中使用原始类型.未来版本的Java编程语言可能会禁止使用原始类型.
尝试将参数化类型的类型成员用作原始类型是编译时错误.
这意味着禁止"稀有"类型扩展到限定类型参数化的情况,但我们尝试将内部类用作原始类型:
Run Code Online (Sandbox Code Playgroud)Outer<Integer>.Inner x = null; // illegal这与我们上面讨论的情况相反.这种半烤型没有实际的理由.在遗留代码中,不使用任何类型参数.在非遗留代码中,我们应该正确使用泛型类型并传递所有必需的实际类型参数.
请注意,Inner类具有独立于Outer类的自己的类型参数,并且它仍然被擦除.基本上他们不希望我们在同一个实例上混合原始类型和泛型类型,因为它在任何版本中都没有意义(在1.5之前,通用部分将是一个错误,在1.5+原始类型不鼓励,并且甚至可以从将来的版本中删除)
然后还有这个:
未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.8节,第9.4节)或非静态字段(第8.3节)M的类型是其类型的擦除在对应于C的泛型声明中.原始类型C的静态成员的类型与对应于C的泛型声明中的类型相同.
将实际类型参数传递给未从其超类或超接口继承的原始类型的非静态类型成员是一个编译时错误.
表示构造函数,实例方法和非静态字段在原始实例中将被视为raw.无论如何,静态成员将被视为通用成员,因为它们不需要加入实例.