理解Java泛型

來源:互聯網
上載者:User

Java泛型的實現原理

泛型,就是一個參數化了的類或介面。裸類型(raw type)就是指去掉了型別參數資訊的類型。Java 為了保持相容性,泛型的實現並不像在C#中那麼徹底,看下面一個具體的泛型類,

public class Node<T, U extends Number> {private T data;private List<U> list;private Node<T> next;public Node(T data, Node<T> next) {this.data = data;this.next = next;}               public void setData2(List<U> l) {list = l; }public U getFirstData(){return list.get(0); }public T getData() { return data; }// ...    }
在編譯這個泛型的時候,編譯器會做一個叫做去泛型型別(Erasure of Generic Types)的處理,具體的處理內容如下:

[1] 泛型型別參數被直接去掉,並把所有的型別參數進行替換。對有Bounded的參數,則使用相應的邊界類型,例如,如果泛型參數是<U extends Number>,那麼這個參數會被直接轉換為Number。如果是類型是像我們上面的這種<T>,那麼<T>會被裝換為Object。
[2] 進行必要的類型裝換,以保證型別安全。
[3] 產生橋接方法保證整合泛型型別時,多態特性仍然工作正常。

 

去泛型型別(Erasure of Generic Types)和相關的強制類型轉換

這個主要和[1]、[2] 兩條相關,根據第[1]條,Java編譯器會把這個泛型類編譯為如下:
//型別參數被直接去掉   public class Node {   //型別參數T被替換為Object   private Object data;   //U被替換為Number   private List data2;   //型別參數被直接去掉  private Node next;  //型別參數被直接去掉,型別參數T被替換為Object  public Node(Object data, Node next) {  this.data = data;  this.next = next;  }  //U被替換為Number  public void setData2(List l) { list = l; }  //U被替換為Number, 經過必要的類型轉換後,實際會變為 public Number getData2() { return (Number)list.get(0); }  public Number getData2() { return list.get(0); }  //型別參數T被替換為Object  public Object getData() { return data; }  // ...  }

經過這個處理後,我們看看第23行經過處理後的代碼,這裡其實是有問題的。因為list.get(0)返回的是一個Object對象,而getData2方法的傳回值是一個Number類型,Object類型不能直接賦值給Number類型,所以這裡必須做一個強制裝換。這也是我們上面說到的第[2] 條的意義所在,經過第[2] 條的規則,第23行實際上會被編譯為:

public Number getData2() { return (Number)list.get(0); }

這樣,不管我們在使用泛型

的時候使用什麼具體的類型,上面的代碼都是能夠保證型別安全的。例如,

Node<String, Integer> node1 = new Node<String, Integer>();   Node<List, Short> node2 = new Node<List, Short>(); 

在使用的時候,Node<String, Integer>和Node<List, Short>都被轉為了Node進行使用,並沒有Node<String, Integer>和Node<List, Short>這兩種類型的存在。編譯器會進行類型轉換以保證在調用相關方法時的型別安全,這需要做強制類型轉換,比如我們寫如下的代碼:

Node<String, Integer> node1 = new Node<String, Integer>();   Integer somenumber = node1.getData2()

這段代碼會被編譯為類似如下,因為getData2返回的是一個Number類型,這裡必須做一個強制轉換:

 Node<String, Integer> node1 = new Node<String, Integer>();   Integer somenumber = (Integer)node1.getData2();

 

橋接方法(Bridge Methods)

先看一個例子如下(例子照搬Oracle的相關文檔):

public class Node<T> {   private T data;   public Node(T data) { this.data = data; }   public void setData(T data) {   System.out.println("Node.setData");   this.data = data;  }  }  public class MyNode extends Node<Integer> {  public MyNode(Integer data) { super(data); }  public void setData(Integer data) {  System.out.println("MyNode.setData");  super.setData(data);  }  }

更具我們前面已經講到的,這段代碼在經過去泛型型別(Erasure of Generic Types)後,會變為如下的樣子:

 

public class Node { private Object data;   public Node(Object data) { this.data = data; }  public void setData(Object data) {  System.out.println("Node.setData"); this.data = data;  }  } public class MyNode extends Node { public MyNode(Integer data) { super(data); } public void setData(Integer data) {  System.out.println(Integer data);  super.setData(data);  }  }

注意看這裡,經過去泛型型別(Erasure of Generic Types)後,考慮如下的代碼:

MyNode mn = new MyNode(5);Node n = (MyNode)mn;  n.setData("Hello");  mn.data //??

這裡特別注意第3行,因為基類和子類分別有一個setData(Object)和setData(Integer)方法,由於方法的參數不同,這兩個實際上是重載方法,所以第三行回去調用Node的setData(Object)。所以,這個時候data到底是個什麼值?明顯這裡是有問題的,繼承的多態性沒有儲存下來。這裡就需要做我們之前提到的第[3]條了,編譯器會給子類添加一個setData(Object)方法,這個方法稱為橋接方法如下:

class MyNode extends Node {   //編譯器自動產生的橋接方法  public void setData(Object data) {setData((Integer) data);  }   public void setData(Integer data) {   System.out.println("MyNode.setData"); super.setData(data);  }  // ...  }

現在再看下面的代碼:

MyNode mn = new MyNode(5);Node n = (MyNode)mn;n.setData("Hello");

這裡的setData會去調用基類的方法,當然,這裡運行時是會出錯的,因為無法將字串轉為整型。這裡目的就是保持泛型繼承的多態性。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.