![](/img/trans.png)
[英]Create instance of generic type in Java when parameterized type is contained?
[英]Create instance of generic type in Java when parameterized type passes through hierarchies?
我一直在閱讀問題的答案:
我已經實施了Lars Bohl建議的方法。 我修改了他的代碼,如下所示:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class ParameterizedTypeEg<E> {
public Class<E> getTypeParameterClass() {
Type type = getClass().getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) type;
return (Class<E>) paramType.getActualTypeArguments()[0];
}
private static class StringHome extends ParameterizedTypeEg<String> {
private String _string;
StringHome (String string) {
_string = string;
}
}
public static void main(String[] args)
throws InstantiationException, IllegalAccessException {
String str = new StringHome("my string").getTypeParameterClass().newInstance();
String str2 = new ParameterizedTypeEg<String>().getTypeParameterClass().newInstance();
}
}
這種方法對於str變量很好用。 然后創建str2,在我看來它是相同的類型(ParameterizedTypeEg <String>,與StringHome基本相同)。 但是,該方法不適用於str2,並且在嘗試轉換(ParameterizedType)類型時會引發ClassCastException。
即使對於str2,我已經使用String參數化了ParameterizedTypeEg,但getGenericSuperclass()返回的內容與str截然不同。 同樣,在方法中,str2將“ this”顯示為ParameterizedTypeEg,而對於str,“ this”顯示為ParameterizedTypeEg $ StringHome。 我想這是問題的根源。 為什么Java不會也為str2確定了泛型類型?
當參數化類型通過多層層次結構傳遞時,我遇到了似乎同樣的問題? 也就是說,類B <T>包含A <T>,並且我實例化了一個B。在A中,我無法通過使用上述方法確定A的參數化類型來創建String對象。 在包含層次結構的情況下,該方法也會產生異常。 這給我帶來了一個問題,因為我希望能夠通過多個級別的包含和/或繼承傳遞參數化類型,並在所有情況下都采用相同的方法生成泛型類型的實例。
謝謝,約翰
進行以下更改,您的代碼將起作用:
從
String str2 = new ParameterizedTypeEg<String>().getTypeParameterClass().newInstance();
至
String str2 = new ParameterizedTypeEg<String>(){}.getTypeParameterClass().newInstance();
這將創建ParameterizedTypeEg的匿名子類。 你打電話時
getClass().getGenericSuperclass();
在StringHome上,您將獲得所需的ParameterizedTypeEg <java.lang.String>。 如果像您那樣創建str2,則該調用僅返回Object,因此將其強制轉換為參數化類型的嘗試失敗:
線程“主”中的異常java.lang.ClassCastException:無法將java.lang.Class強制轉換為java.lang.reflect.ParameterizedType
創建匿名子類將使此返回ParameterizedTypeEg <java.lang.String>
這與Google Guice Guave庫(btw)的Type Token類中使用的技巧相同。 你寫,例如
new TypeToken<List<String>>() {}
並不是
new TypeToken<List<String>>()
getClass().getGenericSuperclass();
為您提供超類的詳細信息。 因此,只有在您將參數化超類作為子類時,它才起作用。 如果實例化給定類型參數的參數化超類,則它將無法正常工作。
但是,該方法不適用於str2,並且當我嘗試強制轉換(ParameterizedType)類型時拋出ClassCastException
...........為什么Java也看不到為str2確定了泛型?
如oracle doc中為ParameterizedType所指定:
ParameterizedType表示參數化類型,例如
Collection<String>
但是, ParameterizedTypeEg
超類是Object,而不是泛型類型。 因此,由getClass().getGenericSuperclass();
返回的Type
getClass().getGenericSuperclass();
是對象本身的Class
。 將非參數化類型的類型強制轉換為ParameterizedType
可以為str
提供ClassCastException
。
為什么Java不會也為str2確定了泛型類型?
運行時的對象沒有任何類型參數信息。 基本上,要執行.newInstance()
創建對象,您需要在運行時擁有類對象,這意味着您必須將其存儲在某處以獲取它。
它對str
起作用的原因恰好是因為String
類型存儲在類元數據中的某個位置。 類具有元數據,其中包括超類和超接口,如果是內部類則將其封閉,字段和方法的類型(方法的返回類型和參數類型)。 所有這些信息都與泛型一起在運行時存儲在字節碼中(其原因是Java中的文件可以單獨編譯,因此在編譯一個使用已編譯文件中的類的文件時,編譯器必須能夠查看類文件並查看泛型信息),並且可以在運行時通過對類對象的反射獲得。
因此,基本上, StringHome
類充當String
類對象的“存儲”,因為在編譯時將String
硬編碼為StringHome
類的類型參數。 因此,在運行時,您可以從此“存儲”中獲取它。
也就是說,類B <T>包含A <T>,並且我實例化了一個B。在A中,我無法通過使用上述方法確定A的參數化類型來創建String對象。
從上面的討論中,您可能會發現關鍵是要在運行時以某種方式“獲取” T
類的類對象。 創建子類A<T>
類將無濟於事,因為這樣做的目的是,實際類在編譯時進行了硬編碼,這需要在編譯時知道該類。 我們不知道在編譯時T
是什么類,因此我們不能將其放入元數據中。 我們只能輸入“ T”,即類型變量。
因此,問題又回到了需要為type參數表示的類找到某種方式來傳遞或傳輸類對象。 您不能再依賴任何基於編譯時的機制。 因此,您必須將其傳遞給其他參數或其他參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.