2017-09-27 49 views
5

我正在研究創建代理對象的庫如何工作,特別是我想了解它們如何從聲明的方法中獲取類型。例如流行的Android庫 - 改造:類型擦除如何工作

interface MyService { 

    @GET("path") 
    Call<MyData> getData(); 
} 

我被搞糊塗了 - 它是如何可能從這個接口正是MyData的類不生對象得到什麼?從我的理解類型刪除的原因將刪除放置在通用括號內的任何信息。

我寫了一些測試代碼和令人驚訝的對我來說是很容易從這樣的代碼獲取類型:

@org.junit.Test 
public void run() { 
    Method[] methods = Test.class.getDeclaredMethods(); 
    Method testMethod = methods[0]; 
    System.out.println(testMethod.getReturnType()); 
    ParameterizedType genericType = ((ParameterizedType) testMethod.getGenericReturnType()); 
    Class<Integer> clazz = (Class<Integer>) genericType.getActualTypeArguments()[0]; 
    System.out.println(clazz); 
} 

interface Test { 
    List<Integer> test(); 
} 

它看起來有點髒,但它的工作原理,並打印Integer。這意味着我們在運行時有類型。此外,我讀過有關另一使壞無名類:

System.out.println(new ArrayList<Integer>().getClass().getGenericSuperclass()); 

打印原料AbstractList<E>而這段代碼

System.out.println(new ArrayList<Integer>() { }.getClass().getGenericSuperclass()); 

打印ArrayList<Integer>

這並不是最後一件讓我困惑的事情。在科特林有物化仿製藥從它看起來像在編譯時的一些技巧,但我們可以很容易地從通用獲取類:

inline fun <reified T> test() { 
    print(T::class) 
} 

而且現在我有類型擦除機制完全糊塗了。

  1. 有人可以解釋一下,爲什麼有時候它持有信息,有時不會?
  2. 爲什麼泛型沒有在Java中以正常的方式實現?是的,我讀過它可能會破壞以前的版本compabillity,但我想了解如何。爲什麼泛型返回類型不會破壞任何東西,但new ArrayList<Integer>呢?
  3. 爲什麼匿名類持有泛型類型,而不是類型擦除?

更新時間: 4.如何具體化的泛型工作在科特林以及爲什麼這樣酷的事情不能用Java實現?

Here解釋了物化泛化的工作原理。 @Mibac

您只能使用reified與內聯函數的組合。這樣的函數使得編譯器將函數的字節碼複製到每個使用該函數的地方(該函數正在被 「內聯」)的每個 位置。當您使用具體化類型調用內聯函數時, 編譯器知道用作類型參數的實際類型,並將生成的字節碼修改爲直接使用相應的類。 因此,像myVar這樣的調用是T成爲myVar是字符串,如果類型 參數是字符串,在字節碼和運行時。

+3

[工作原理](https://stackoverflow.com/a/45952201/3533380) – Mibac

回答

3

有人可以解釋一下,爲什麼有時它會保存信息,有時卻不會?

JVM的水平存在Signature attribute是:

記錄簽名(§4.7.9.1)的一類,接口,構造函數,方法或字段的聲明在Java編程語言使用類型變量或參數化類型。

一個爲什麼你可能想擁有它的原因之一是,例如,編譯器需要知道實際的類型來自預編譯some.class一個some_method的說法(即來自第三方some.jar)。在這種情況下,假設該方法需要Object可能違反了編譯some.class的假設,並且您不能以類型安全的方式調用some_method

爲什麼匿名類保存通用類型,而不是類型擦除?

當你撥打:

System.out.println(new ArrayList<Integer>().getClass().getGenericSuperclass()); 

...沒什麼JVM類方面得到確定,而這一點:

System.out.println(new ArrayList<Integer>() { }.getClass().getGenericSuperclass()); 

...實際上定義了類jvm級別,albiet匿名,java語言級別

這就是爲什麼反射給這些情況帶來不同結果的原因。

爲什麼泛型沒有以正常的方式在Java中實現?是的,我讀過它可能會破壞以前的版本compabillity,但我想了解如何。爲什麼泛型返回類型不會破壞任何東西,除了新的ArrayListdoes?

如何具體化的泛型工作在科特林以及爲什麼這樣酷的事情不能用Java實現?

我不認爲你可以給出客觀的答案,這是不是基於意見的這些。此外,我建議分裂或縮小你的問題的範圍。