簡體   English   中英

在Java中實現ArrayList時鍵入擦除

[英]type erasure in implementation of ArrayList in Java

我正在閱讀關於Java Generics的這篇文章,並且在那里提到了ArrayList的構造函數看起來像這樣:

class ArrayList<V> {
  private V[] backingArray;
  public ArrayList() {
    backingArray = (V[]) new Object[DEFAULT_SIZE]; 
  }
}

我無法理解編譯器的類型擦除和類型檢查是如何解釋的那樣。 我得到的一點是type參數被轉換為Object類型。

我會想象它(用Object替換所有V ),但這絕對是錯誤的。

class ArrayList<Object> {
      private Object[] backingArray;
      public ArrayList() {
        backingArray = (Object[]) new Object[DEFAULT_SIZE]; 
      }
}

它究竟是如何轉換為Object類型但仍保留V的類型安全性? 當我有ArrayList<String>ArrayList<Integer> ,每個都有兩個不同的類? 如果不存在,那么存儲StringInteger的類型信息在哪里?

您的類型擦除版本不正確。 類型參數聲明不會被刪除到Object但只會刪除它的用法。 進一步來說:

  • 擦除泛型類型是其對應的原始類型。 因此,對於ArrayList<V> ,它只是ArrayList
  • 類型參數的擦除是其最左邊界限。
  • 並且所有類型參數都被刪除了。 類型參數是在實例化泛型類時使用的參數。 因此, ArrayList<Integer>將替換為ArrayList

所以,正確的擦除版本將是:

class ArrayList {
    private Object[] backingArray;
    public ArrayList() {
      backingArray = (Object[]) new Object[DEFAULT_SIZE]; 
    }
}

當我有ArrayList和ArrayList時,每個都有兩個不同的類?

不,情況絕對不是這樣。 編譯器僅生成泛型類型或方法的一個字節代碼表示,並將泛型類型或方法的所有實例映射到唯一表示。

如果沒有存儲String和Integer的類型信息的位置?

當編譯器執行類型擦除時,它會根據一些預定義的規則刪除所有類型信息,偶爾添加所謂的橋接方法 ,並添加所需的所有必要類型轉換。

因此,例如,以下使用ArrayList<Integer>ArrayList<String>

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
int value = list.get(0);

ArrayList<String> list2 = new ArrayList<String>();
list.add("A");
String value2 = list.get(0);

將轉換為有點像這樣:

ArrayList list = new ArrayList();
list.add(1);
int value = (Integer) list.get(0);

ArrayList list2 = new ArrayList();
list.add("A");
String value2 = (String) list.get(0);

進一步閱讀:

你的第二個例子不正確。 類型擦除並不意味着全局將所有內容都轉換為Object 正如你猜測的那樣,這幾乎沒有任何意義。 相反,什么類型的擦除做(字面上)以下(借用Jon Skeet ):

List<String> list = new ArrayList<String>();
list.add("Hi");
String x = list.get(0);

這段代碼被翻譯成:

List list = new ArrayList();
list.add("Hi");
String x = (String) list.get(0);

注意轉換為String ,而不僅僅是一個vanilla Object 類型擦除“擦除”泛型的類型並將其中的所有對象強制轉換為T 這是一種添加一些編譯時用戶友好性而不會產生運行時成本的聰明方法。 但是,正如文章所聲稱的那樣,這並非沒有妥協。

請考慮以下示例:

ArrayList<Integer> li = new ArrayList<Integer>();
ArrayList<Float> lf = new ArrayList<Float>();

它可能看起來不直觀(或正確),但li.getClass() == lf.getClass()將評估為true。

好問題。首先進行類型檢查。如果所有內容都編譯(即,在提供編譯類型安全性之后),則會發生類型擦除。

同樣,很多事情都是類型擦除的一部分,其中包括: -

1)Adding casts 
2) creating bridge methods

但是首先進行類型檢查,一切都在以后進行

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM