结合原始类型和通用方法

Edw*_*rzo 26 java generics raw-types generic-method

这是一个问题,第一个代码清单编译得很好(JDK 1.6 | JDK 1.7):

ArrayList<String> a = new ArrayList<String>();
String[] s = a.toArray(new String[0]);
Run Code Online (Sandbox Code Playgroud)

但是,如果我将List引用声明为原始类型:

ArrayList a = new ArrayList();
String[] s = a.toArray(new String[0]);
Run Code Online (Sandbox Code Playgroud)

我收到编译器错误,说明String[]是必需的,但是Object[]找到了.

这意味着我的编译器将泛型方法解释为返回,Object[]尽管String[]它接收了一个as参数.

我加倍检查了toArray(myArray)方法签名:

<T> T[] toArray(T[] a);
Run Code Online (Sandbox Code Playgroud)

因此,它是一个参数化方法,其类型参数<T>与List(即<E>)的类型参数无关.

我不知道在这里使用原始类型如何影响使用独立类型参数的参数化方法的评估.

  • 有谁知道为什么这段代码不能编译?
  • 有没有人知道记录这种行为的任何参考?

Mar*_*ers 31

它并不完全符合您的期望,但如果您以原始形式引用泛型类,则会失去以任何方式使用泛型的能力,例如成员.它也不限于通用方法,请查看:

 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!
Run Code Online (Sandbox Code Playgroud)

这是JLS(4.8)的相关部分:

的类型构造函数(§8.8),实例方法的(8.4节,第9.4节),或者非静态字段(§8.3),其不从其超类或超接口继承的原类型C的M是原始类型对应在对应于C的通用声明中擦除其类型


Pre*_*raj 8

当你不使用泛型编译器将其视为原始类型,因此每个泛型类型都会变成Object因此String[]它不能通过因为它需要Object[]
所以这里是交易 - 如果你使用

List l = new ArrayList<String>();
Run Code Online (Sandbox Code Playgroud)

您使用的是原始类型,其所有实例成员都被其擦除对象替换.特别是出现在实例方法声明中的每个参数化类型都被其原始对应物替换.有关详细信息,请参阅JLS 4.8.


Per*_*ion 6

这是我在规范中找到的最接近的描述来描述这种观察到的行为:

未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.8节,第9.4节)或非静态字段(第8.3节)M的类型是其类型的擦除在对应于C的泛型声明中.原始类型C的静态成员的类型与对应于C的泛型声明中的类型相同.

将实际类型参数传递给未从其超类或超接口继承的原始类型的非静态类型成员是一个编译时错误.

基于上述和观察到的行为,我认为可以安全地说所有通用参数类型都从原始类型中删除.当然,在非遗留代码中不鼓励使用原始类型:

原始类型的使用仅允许作为遗留代码兼容性的让步.强烈建议不要在将通用性引入Java编程语言之后编写的代码中使用原始类型.未来版本的Java编程语言可能会禁止使用原始类型.