原生类型 和 参数化类型

来源:互联网 发布:720云全景软件 编辑:程序博客网 时间:2024/05/16 08:26

 import java.util.*;
public class Pair<T> {
private final T first;
private final T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T first() {
return first;
}
public T second() {
return second;
}
public List<String> stringList() {
return Arrays.asList(String.valueOf(first),
String.valueOf(second));
}
public static void main(String[] args) {
Pair p = new Pair<Object> (23, "skidoo");
for (String s : p.stringList())
System.out.print(s + " ");
}
}

上面这个程序会编译出错的

解释如下:

1。
这个十分奇怪的现象是因为程序使用了原生类型(raw type)而引起的。一个原
生类型就是一个没有任何类型参数的泛型类或泛型接口的名字。例如,List<E>
是一个泛型接口,List<String> 是一个参数化的类型,而List 就是一个原生
类型。在我们的程序中,唯一用到原生类型的地方就是在main 方法中对局部变
量p 的声明:
Pair p = new Pair<Object> (23, "skidoo");

一个原生类型很像其对应的参数化类型,但是它的所有实例成员都要被替换掉,
而替换物就是这些实例成员被擦除掉对应部分之后剩下的东西。具体地说,在一
个实例方法声明中出现的每个参数化的类型都要被其对应的原生部分所取代
[JLS 4.8]。我们程序中的变量p 是属于原生类型Pair 的,所以它的所有实例方
法都要执行这种擦除。这也包括声明返回List<String>的方法stringList。编
译器会将这个方法解释为返回原生类型List。

2。
当List<String>实现了参数化类型Iterable<String>时,List 也实现了原生类
型Iterable。Iterable<String>有一个iterator 方法返回参数化类型
Iterator<String>,相应地,Iterable 也有一个iterator 方法返回原生类型
Iterator。当Iterator<String>的next 方法返回String 时,Iterator 的next
方法返回Object。因此,循环迭代p.stringList()需要一个Object 类型的循环
变量,这就解释了编译器的那个奇怪的错误消息的由来。这种现象令人想不通的
原因在于参数化类型List<String>虽然是方法stringList 的返回类型,但它与
Pair 的类型参数没有关系,事实上最后它被擦除了。

3。
。正确解决这个问题的方法是为局部变量p 提供一个合适的
参数化的声明:Pair<Object> p = new Pair<Object>(23, "skidoo");
以下是要点强调:原生类型List 和参数化类型List<Object>是不一样的。
替代程序如下:

public static void main(String[] args)
 {
  Pair<Object> p = new Pair<Object> (23, "skidoo");
  List<String> l=p.stringList();
  for (String s : l)
  System.out.print(s + " ");
 }

4。
:List<?>是一种特殊的参数化类型,
被称为通配符类型(wildcard type)。像原生类型List 一样,编译器也不会知
道它接受哪种类型的元素,但是因为List<?>是一个参数化类型,从语言上来说
需要更强的类型检查。为了避免出现ClassCastException 异常,编译器不允许
你添加除null 以外的任何元素到一个类型为List<?>的list 中。