[英]Instantiate and apply generic method with unknown generic type - Java
我需要實例化具有未知通用類型的對象,然后對其應用通用方法。 我站在這里:
public static void main(String[] args)
{
BarIf bar = newRandomBarImpl();
Foo foo1 = newFooBar(bar.getClass()); // warning
Foo<?> foo2 = newFooBar(bar.getClass()); // error
Foo<? extends BarIf> foo3 = newFooBar(bar.getClass()); // error
foo1.doSomething(bar); // warning
foo2.doSomething(bar); // error
foo3.doSomething(bar); // error
}
static <T extends FooIf<S>, S extends BarIf> T newFooBar(Class<S> barClass){}
static <T extends BarIf> T newRandomBarImpl(){}
interface FooIf<T extends BarIf>
{
public void doSomething(T t);
}
interface BarIf{}
class Foo<T extends BarIf> implements FooIf<T>
{
public void doSomething(T t){}
}
奇怪的是,對於foo2和foo3,newFooBar()方法返回FooIf而不是Foo。 我猜類型推斷是一團糟。 但是由於我不知道Bar類型,所以無法傳遞方法的通用參數。
我需要的是Foo<bar.getClass()>
。 有辦法嗎?
我嘗試使用TypeToken,但最終得到的是T類型而不是實際的Bar類型。 有機會使用嗎?
首先,像
static <T extends BarIf> T newRandomBarImpl(){}
廢話 它基本上說:“無論調用者用什么替換T
,該方法都將返回它”。 換句話說,你可以寫
ArbitraryTypeExtendingBarIf x=newRandomBarImpl();
沒有得到編譯器警告。 顯然,這是行不通的。 newRandomBarImpl()
對ArbitraryTypeExtendingBarIf
一無所知。 方法名稱建議您實際上要表達newRandomBarImpl()
可以返回BarIf
的任意實現,但這是對BarIf
的不必要使用,
BarIf newRandomBarImpl(){}
已經表示此方法可以返回BarIf
的任意子類型。 實際上,由於BarIf
是抽象類型,因此此方法必須返回BarIf
的子類型,並且在任何地方都沒有指定它將是哪種類型。
聲明同樣如此
static <T extends FooIf<S>, S extends BarIf> T newFooBar(Class<S> barClass){}
它還聲稱,調用者可以選擇FooIf
方法將返回的實現。 正確的聲明是
static <S extends BarIf> FooIf<S> newFooBar(Class<S> barClass){}
該方法決定返回的FooIf
實現,而不是調用方。
關於您處理FooIf
的其他嘗試,您不能使用帶通配符參數化的類型來以這種方式工作,也不能使用Reflection對其進行修復。 但是您可以使用類型參數編寫通用代碼:
public static void main(String[] args)
{
BarIf bar = newRandomBarImpl();
performTheAction(bar.getClass(), bar);
}
static <T extends BarIf> void performTheAction(Class<T> cl, BarIf obj) {
FooIf<T> foo=newFooBar(cl);
foo.doSomething(cl.cast(obj));
}
static <S extends BarIf> FooIf<S> newFooBar(Class<S> barClass){}
static BarIf newRandomBarImpl(){}
interface FooIf<T extends BarIf> {
public void doSomething(T t);
}
interface BarIf{}
performTheAction
方法是通用的,換句話說,它適用於表示為類型參數T
的未知類型。 可以使用未知類型調用此方法? extends BarIf
如main
方法中所示? extends BarIf
。
但是,請記住,每個對類型X
引用都意味着所引用的對象可能具有X
的子類型,而不必擔心它。
您可以在此處簡單地使用基類BarIf
,而不管對象的實際BarIf
子類型為:
BarIf bar = newRandomBarImpl();
FooIf<BarIf> foo=newFooBar(BarIf.class);
foo.doSomething(bar);
請注意,當您要使用接口中未指定的實際實現類型Foo
方法時,必須將FooIf
為Foo
。 您可以將FooIf<BarIf>
為Foo<BarIf>
而不發出警告,因為如果Foo<X> implements FooIf<X>
,則泛型類型轉換是正確的。
但是,它可能會在運行時失敗,因為不需要newFooBar
方法來返回Foo
實例而不是其他任何FooIf
實現。 這就是為什么顯式類型轉換是唯一正確的解決方案的原因,因為它記錄了有關對象的實際運行時類型的假設。 所有其他嘗試將在某處生成至少一個編譯器警告。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.