簡體   English   中英

類型擦除 Generics

[英]Type erasure Generics

編譯時在 new T[5] 處發生錯誤 => error: generic array creation 根據我的理解,該數組是在編譯時創建的,因為我們在編譯時不知道 T 的類型我們不能實例化一個數組。 但是,如果 T 在編譯時被擦除並更改為 Object 那么為什么仍然會出現此錯誤? 因為我們可以創建一個 Object 的數組。

// Before Compiling 
public class GenericClass<T> {
    GenericClass(){
        T[] obj = new T[5];
    }
}

// After Compiling
public class GenericClass {
GenericClass() {
Object[] obj = new Object[5];
}
}

類似的情況,比如,

public class GenericClass<T> {
        GenericClass(){
            T obj = new T(); }}

/*  error :required: class
  found:    type parameter T
  where T is a type-variable:
  T extends Object declared in class GenericClass*/

根據我的理解,數組是在編譯時創建的

不,數組是在運行時創建的。

並且因為我們在編譯時不知道 T 的類型,所以我們不能實例化一個數組。

正確的。

但是,如果 T 在編譯時被擦除並更改為 Object 那么為什么仍然會出現此錯誤?

因為“它在編譯時被擦除並更改為對象”被過於簡單化了。

此外,generics 和 arrays 彼此不友好。 問題是,在 generics 部分被擦除的地方,arrays不會那樣工作 你可以這樣做:

String[] x = new String[10];
tellMeTheTypeOfMyArray(x);

void tellMeTheTypeOfMyArray(Object[] o) {
  System.out.println("Your array's component type is: " + o.getClass().getComponentType());
}

此代碼將編譯並正常工作,沒有錯誤,並打印:

Your array's component type is: java.lang.String

與 generics 相比,您不能在其中編寫此類方法。 你不可能這樣做:

List<String> x = new ArrayList<String>();
tellMeTheTypeOfMyList(x);

void tellMeTheTypeOfMyList(List<?> o) {
  System.out.println("Your list's component type is: " + ??????);
}

工作。 這里不可能有 java 代碼,沒有什么可以代替 ?????? 打印 String,因為該信息在運行時根本不存在了。

想象一下這段代碼:

// This is written by Wahab today.

class Example<T> {
  protected T[] arr;

  Example() {
    this.arr = new T[10];
  }
}

它像你想要的那樣工作。 然后我做:

// Written by me, a year later
class Uhoh extends Example<String> {
  Uhoh() {
    super();
  }

  void hmmm() {
    System.out.println(this.arr.getComponentType());
  }
}

我顯然期望,不,要求 - 這會打印java.lang.String ,但它不可能這樣做 因為這很奇怪和令人困惑,java 有一個規則:如果你編譯你的代碼並且你沒有看到任何關於 generics 問題的警告(並且沒有@SuppressWarnings將它們消除),那么這種混淆不太可能發生。

允許您編寫new T[]並以這種愚蠢的方式編寫new Object[]被認為太過分了。

那么如何將 arrays 與 generics 類型一起使用呢?

java.util.ArrayList相同的方式: Do not use generics here Arrays 如果您打算在通用代碼中創建它們,則幾乎不應該有T類型。 如果你的代碼庫中的任何地方都有一個T[] ,那么這意味着你永遠不應該為它做任何事情——讓你new代碼的調用者為你做。 如果您確實想自己new new arrays,請不要使用 T,使用Object[]作為類型,並在需要時轉換為 T。 這就是 java 內置 ArrayList class 的工作原理。 一些摘錄直接從其來源復制粘貼:

    transient Object[] elementData; // non-private to simplify nested class access

    public E get(int index) {
        Objects.checkIndex(index, size);
        return elementData(index);
    }

    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

這是一個示例,同樣直接來自 ArrayList 的來源(或者更確切地說, java.util.Collection定義了它,而 ArrayList 繼承了它),您讓調用者為您提供代碼來生成 arrays:

    default <T> T[] toArray(IntFunction<T[]> generator) {
        return toArray(generator.apply(0));
    }

在這里,調用者提供了一個 function,它將一個int轉換為一個T[] - 它采用了執行new String[10]的概念並將其轉換為一個 function,然后您將其傳遞給 toArray 方法,該方法將使用它(感覺在這里可以隨意忽略它是如何使用它的,這是一個有點奇怪的解決方案。它有效,只是 - 不確定你是否應該學習那部分的課程)。

你像這樣使用它:

List<String> listOfStrings = ...;
String[] convertedToArray = listOfStrings.toArray(String[]::new);

Java arrays 在運行時知道它們的組件類型。 創建數組時,必須在運行時提供組件類型。 但是在您的GenericClass中,它不能這樣做,因為它在運行時不知道T是什么。 如果它創建一個Object[] ,那么 object 將具有錯誤的運行時 class,並且如果T不是Object ,則該實例與類型T[]不兼容。 你是對的,在 class 中,沒有立即出錯。 但是如果變量是T[]的聲明暴露給外部 scope,它期望T是一個更具體的類型,它可能會導致ClassCastException

// Before type erasure 
class GenericClass<T> {
    T[] obj;
    GenericClass() {
        obj = new T[5]; // if hypothetically you could do this
    }
    T[] getObj() {
        return obj;
    }
}
class MyCode {
    public static void main(String[] args) {
        GenericClass<String> foo = new GenericClass<>();
        String[] strings = foo.getObj(); // no casts needed; no warnings
    }
}

// After type erasure
class GenericClass {
    Object[] obj;
    GenericClass() {
        obj = new Object[5];
    }
    Object[] getObj() {
        return obj;
    }
}
class MyCode {
    public static void main(String[] args) {
        GenericClass foo = new GenericClass();
        String[] strings = (String[]) foo.getObj(); // ClassCastException at runtime
    }
}

暫無
暫無

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

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