[英]Generics: Get name of instance
我有一個返回List<Property<?>>
。
屬性是具有一個通用參數的類型:
public class Property<T extends Comparable<T>> { ... }
有一個混合類型屬性的列表,我不知道具體元素具有什么類型參數。
我想做那樣的事情:
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = new PropertyWrapper(crt.getGenericType());
// I know this doesn't exist ----^
}
在一句話中:我需要PropertyWrapper
具有與當前Property
相同的通用模板參數。 有沒有辦法做到這一點?
我可以應用https://stackoverflow.com/a/3437930/146003中所述的建議,但即使我這樣做,如何實例化相應的PropertyWrapper<XXX>
然后,只有一個Class<T>
的實例?
如果需要,我可以修改Property<?>
。 我也不介意是否需要使用反射(我認為它需要)
編輯:我忘記了什么。 事實上,我無法通過線路實現包裝
PropertyWrapper<?> crtWrapper = new PropertyWrapper(crt.getGenericType());
因為我有專門的子類( PropertyWrapper_String
)。
現在我看到兩種可能性:
1:按字符串對類進行Instanciate:
String strGenericType = "";
Class<?> wrapperClass = Class.forName("PropertyWrapper_" + strGenericType);
2:有沒有辦法在不創建子類的情況下專門化泛型類?
非常感謝您的提示
嘗試創建以下方法:
<T> PropertyWrapper<T> createWrapper(Property<T> property){
return new PropertyWrapper<T>(property);
}
然后這樣稱呼它。
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = createWrapper(crt);
}
上述工作的原因是泛型類型T
是從參數推斷出來的,並且被鎖定為整個方法。 不像使用<?>
在環路,其中的每一個實例<?>
被推斷為是不同的類型。
編輯:
要根據包裝器中的類來處理具有不同類類型的問題,請考慮一個Map,其中鍵是要包裝的類,值是包裝器。
Map<Class<?>, Class<?>> myMap;
那么你可以這樣:
Class<?> wrappedType = property.getGenericType();
Class<?> wrapperClass = myMap.get(wrappedType);
PropertyWrapper<?> wrapper = (PropertyWrapper<?>) wrapperClass.newInstance();
雖然如果需要傳遞參數,可能需要執行類似的操作。
Constructor<?> constructor = wrapperClass.getDeclaredConstructor(property.getClass());
PropertyWrapper<?> wrapper = (PropertyWrapper<?>) constructor.newInstance(property);
如果你有一個Class<T>
你可以只取這個類,通過在類對象上調用newInstance()
並將其newInstance()
轉換為T
來創建一個實例。
你遇到的問題是得到crt
的泛型參數。 如果您具有Property
具體子類,例如StringProperty extends Property<String>
,則可以使用反射獲取類型。 但是,如果只創建Property<T>
實例而沒有具體的子類,並且您不知道列表的元素在何處創建,那么AFAIK就不可能獲得泛型類型(即使您知道元素的創建位置)可能是不可能的)。
因此,您可能獲得屬性包裝器以了解屬性類型的唯一方法可能是將類型參數(類)存儲在屬性本身中。 然后包裝器可以查詢屬性的類型/類成員變量。
編輯 :為什么這是不可能的或至少非常困難的一些解釋。
泛型的問題在於,由於類型擦除,當使用new Property<SomeType>()
創建屬性時,泛型類型會丟失。 這里沒有可用於檢索SomeType
運行時信息。
如果您有具體的子類(定義具體的泛型類型),那么您可以在運行時獲得每個類的泛型參數所在的反射信息。 然后,您可以獲取每個屬性的實際類,並檢索該類的反射數據。
如果您有定義這些類型的方法或字段並返回/保持對屬性的引用,這也是可能的。 但是,我懷疑你有這些信息,因為你似乎得到了一些列表,並且不確切知道該列表的元素在何處以及如何創建。
我進一步假設屬性'類只是Property
,而不是子類。 因此,唯一的方法是自己提供運行時信息,即通過將類型類的引用作為構造函數參數傳遞。
好的,我要回答自己。
我現在將Class<?>
的實例傳遞給Property
-class。
然后我提取屬性的基本名稱,然后簡單地刪除"java.lang."
這可能與大多數情況一樣,我這樣做是為了原始數據類型 - resp。 他們的自動裝箱課程。
此外,我只是通過名稱實例化包裝器的新實例,並將to be wrapped屬性作為參數傳遞給適用於該構造函數的構造函數。
這里有一些感興趣的代碼:
String template = "..."; // some package definition
for (Property<?> crt : bag)
{
String className = template + crt.getClassName();
Class<? extends PropertyWrapper<?>> wrapperClass = null;
wrapperClass = (Class<? extends PropertyWrapper<?>>) Class.forName(className);
Constructor<? extends PropertyWrapper<?>> constructor = wrapperClass.getConstructor(new Class<?>[] {Property.class});
PropertyWrapper<?> wrapper = constructor.newInstance(crt);
// Further operations using the wrapper
}
為簡單起見,我省略了錯誤處理部分。
而不是從調用站點實例化包裝器,為什么不讓Property
知道如何創建自己的包裝器? 就像是:
public class Property<T extends Comparable<T>> {
PropertyWrapper<T> newWrapper();
}
但這只有一半的幫助。 你真正的問題是在像你這樣的循環中:
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = crt.newWrapper();
}
PropertyWrapper和Property具有“相同”類型這一事實並不是很有用,因為該類型只是未綁定的通配符。
我真的很討厭給出其中一個“你真正想做什么”的答案,但是 - 你真的想做什么? 一般來說,一旦你到達一個未綁定的通配符,所有的希望都會丟失(除非你願意做不安全的,不可檢查的強制轉換或者用反射檢查向后彎曲)。 解決這個問題的一種方法是在將該Property<T>
放入List<Property<?>>
之前,盡可能多地將操作放在Property<T>
中。 我的newWrapper()
就是一個例子:它將創建一個PropertyWrapper<T>
的動作放入Property<T>
本身。 如果您想要在屬性更改時注冊回調,那么您也可以在每個地方執行非通配符Property<Whatever>
。 例如:
Property<UserLogin> property = new Property<UserLogin>();
SomeListener<UserLogin> listener = whatever();
property.addListener(listener);
wildcardedPropertiesList.add(property);
這個特殊的例子可能沒有幫助,但希望它會給你適用的想法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.