结合原始types和通用方法
下面是一个问题,第一个代码清单编译得很好(JDK 1.6 | JDK 1.7):
ArrayList<String> a = new ArrayList<String>(); String[] s = a.toArray(new String[0]);
但是,如果我将List
引用声明为原始types:
ArrayList a = new ArrayList(); String[] s = a.toArray(new String[0]);
我得到一个编译器错误,说String[]
是必需的,但是find了Object[]
。
这意味着我的编译器将通用方法解释为返回Object[]
尽pipe接收到String[]
作为其参数。
我加倍检查了toArray(myArray)
方法签名:
<T> T[] toArray(T[] a);
因此它是一个参数化方法,其types参数<T>
与列表(即<E>
)没有任何关系。
我不知道如何在这里使用原始types影响使用独立types参数的参数化方法的评估。
- 有没有人有任何想法为什么这个代码不能编译?
- 有没有人知道这种行为logging的任何参考?
这不完全是你所期望的,但是如果你以原始forms引用一个generics类,那么你将失去以任何方式使用generics的能力,例如成员。 它不限于通用方法,看看这个:
public class MyContainer<T> { public List<String> strings() { return Arrays.asList("a", "b"); } } MyContainer container = new MyContainer<Integer>(); List<String> strings = container.strings(); //gives unchecked warning!
这是JLS( 4.8 )的相关部分:
未从其超类或超接口inheritance的原始typesC的构造函数(第8.8节),实例方法(第8.4节,第9.4节)或非静态字段(第8.3节)M的types是对应的原始types删除对应于C的generics声明中的types
这是我在规范中描述的观察行为中最接近的描述:
未从其超类或超接口inheritance的原始typesC的构造函数(第8.8节),实例方法(第8.8节,第9.4节)或非静态字段(第8.3节)M的types是其types的擦除在对应于C的通用声明中。原始typesC的静态成员的types与对应于C的通用声明中的types相同。
将实际的typesparameter passing给非超类或超接口inheritance的原始types的非静态types成员是编译时错误。
基于上述和观察到的行为,我认为可以安全地说, 所有generics参数types都从原始types中删除。 当然,在非遗留代码中阻止使用原始types本身:
只允许使用原始types作为遗留代码兼容性的一个让步。 强烈build议不要在将通用性引入Java编程语言后编写的代码中使用原始types。 未来版本的Java编程语言可能会禁止使用原始types 。
当你不使用generics时,编译器把它当作一个原始types,因此每个generics都变成了Object
,所以你不能传递String[]
因为它需要Object[]
所以这里是交易 – 如果你使用
List l = new ArrayList<String>();
您正在使用原始types,其所有实例成员都被其擦除对象replace。 特别是出现在实例方法声明中的每个参数化types都被replace为其原始对象。 有关详细信息,请参阅JLS 4.8。
可能有趣的是,这种行为可以被“解决”。 使用两个接口,一个基本非通用接口和一个通用接口。 然后编译器知道基类非generics接口的所有function都不是通用的,并会像这样对待它们。
这种行为是非常烦人的,如果使用stream和函数链,因此我解决它像下面。
通过接口inheritance的说法 :
public interface GenericInterface<X extends Y> extends BaseInterface { X getValue(); } public interface BaseInterface { String getStringValue(); }
现在你可以做下面没有警告或问题:
GenericInterface object = ...; String stringValue = object.getStringValue();
因为你的ArrayList是一个非参数化的列表,所以不能传入toArray()方法,只知道它存放Object,就是这样。 a.toArray()
将始终返回一个Object []数组。 同样,如果你想指定它保存特定的stringtypes,你必须把它转换为(String[])
(其中包含所有的危险)。