有人可以向我解释为什么明显需要为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; } }
这是一个很常见的错误:
ForEachLoop f = new ForEachLoop();
应该
ForEachLoop<Something> f = new ForEachLoop<Something>();
如果您使用原始类型(不应这样做),则编译器将擦除该实例的所有通用信息,即使它不是类型参数T,也使其与1.5版之前的代码兼容。
仅在使用Java 1.4或更低版本进行编写时才使用原始类型,在这种情况下,您不应有任何泛型。在字节码级别,该方法在类型擦除后返回Collection(原始)。通常,如果实例具有通用类型集,则当您尝试对get集合进行操作时,编译器将使用通用信息来决定应返回字符串,然后在字节码级别上,它将自动强制转换从其接收的对象集合到字符串(因为保证是字符串)。但是,如果您使用原始类型,则编译器将忽略所有常规信息,并且不再自动为您强制转换对象。
get
编辑 :在原始类型部分中有这些东西:
上述规则的另一个含义是,原始类型的泛型内部类本身只能用作原始类型: class Outer<T>{ class Inner<S> { S s; } } 不能以部分原始类型(“稀有”类型)访问内部 Outer.Inner<Double> x = null; // illegal Double d = x.s; 因为Outer本身是原始的,所以它的所有内部类(包括Inner)也是原始的,因此无法将任何类型参数传递给它。 仅允许使用原始类型作为对遗留代码兼容性的让步。强烈建议不要在将通用性引入Java编程语言后在代码中使用原始类型。 Java编程语言的未来版本可能会禁止使用原始类型。 尝试将参数化类型的类型成员用作原始类型是编译时错误。 这意味着对“稀有”类型的禁令扩展到对限定类型进行参数化的情况,但是我们尝试将内部类用作原始类型: Outer<Integer>.Inner x = null; // illegal 这与我们上面讨论的情况相反。这种半烘烤类型没有实际的理由。在旧版代码中,不使用任何类型参数。在非遗留代码中,我们应正确使用泛型类型并传递所有必需的实际类型参数。
上述规则的另一个含义是,原始类型的泛型内部类本身只能用作原始类型:
class Outer<T>{ class Inner<S> { S s; } }
不能以部分原始类型(“稀有”类型)访问内部
Outer.Inner<Double> x = null; // illegal Double d = x.s;
因为Outer本身是原始的,所以它的所有内部类(包括Inner)也是原始的,因此无法将任何类型参数传递给它。
仅允许使用原始类型作为对遗留代码兼容性的让步。强烈建议不要在将通用性引入Java编程语言后在代码中使用原始类型。 Java编程语言的未来版本可能会禁止使用原始类型。
尝试将参数化类型的类型成员用作原始类型是编译时错误。
这意味着对“稀有”类型的禁令扩展到对限定类型进行参数化的情况,但是我们尝试将内部类用作原始类型:
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的构造函数(第8.8节),实例方法(第8.8节,第9.4节)或非静态字段(第8.3节)M的类型是对其类型的擦除原始类型C的静态成员的类型与对应于C的泛型声明中的类型相同。
将实际类型参数传递给未从其超类或超接口继承的原始类型的非静态类型成员是编译时错误。
这表示构造函数,实例方法和非静态字段在原始实例中将被视为原始。静态成员无论如何都将被视为通用成员,因为它们不需要访问实例。