原生類型 和 參數化類型

 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 中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章