[英]Java generics puzzler with generic static factory
我最近開始為一個項目編寫一個通用的對象映射器,然后遇到了我不太了解的東西。 給定以下內容:
public class G<X> {
public G(Class<X> c) { }
public void m(X x) { }
public static <T> G<T> create(Class<T> c) {
return new G<T>(c);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
G<?> t = create(o.getClass());
t.m(o);
}
}
我收到以下編譯錯誤:
m(capture#402 of ?) in G<capture#402 of ?> cannot be applied to (java.lang.Object)
我似乎無法找出一種方法來正確地投t
,使這個編譯。 我想念什么? 使用JDK 1.6。
編輯 :
這不是一個學術問題。 我正在嘗試從休眠對象到它們對應的DTO編寫一個映射器,以在REST層中傳遞。 假設對於每個ORM對象Foo
,可能存在一個類FooDTO
,該類具有一個構造函數,該構造函數將Foo
一個實例作為參數。 如果FooDTO
不存在或沒有適當的構造函數, FooDTO
Foo
映射到FooDTO
的泛型類將封裝此假設並拋出適當的異常:
class Mapper<Foo,FooDTO> {
private final Constructor<FooDTO> dtoConstructor;
Mapper(Class<Foo> fooClass, Class<FooDTO> fooDTOClass){
// find the constructor of FooDTO or throw ...
}
public FooDTO map(Foo f){
return dtoConstructor.newInstance(f);
}
// this factory is for convenience when we don't know the type of FooDTO:
public static Mapper<X,Object> create(Class<X> fromClass){
Class<Object> dtoClass = // ... find it
return new Mapper<X,Object>(fromClass,dtoClass);
}
}
如果我傳遞通用對象類來create
這似乎會中斷。
請注意,我的實際實現中所有FooDTO
類都從通用超類擴展而來,即, Mapper
的簽名實際上類似於Mapper<Foo,DTO<Foo>>
。 我認為這無關緊要。
編輯2 :
實際上,建議更改G<?> t = create(o.getClass());
到G<Object> t = (G<Object>) create(o.getClass());
在這種情況下工作。
不幸的是,我沒有意識到我的課更復雜的事實實際上會產生影響。 這是一個更完整的示例(對於零星的問題,我深表歉意):
public class Y<T> {
}
public class G<X, Z extends Y<X>> {
public G(Class<X> c, Class<Z> s) {
}
public void m(X x) {
}
public static <T, S extends Y<T>> G<T, S> create(Class<T> c) {
Class<S> s = null; // find this via some reflection magic
return new G<T, S>(c, s);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
G<? extends Object, Y<? extends Object>> t = create(o.getClass());
t.m(o);
}
}
在這種情況下,使用反射和該類型對象的某些常規位置創建對象Class<S>
。 該部分工作正常,應該與本討論無關。 我現在收到的錯誤如下:
inconvertible types
found : G<capture#155 of ? extends java.lang.Object,Y<capture#155 of ? extends java.lang.Object>>
required: G<java.lang.Object,Y<java.lang.Object>>
如果我將隱含的行更改為:
G<Object, Y<Object>> t = (G<Object, Y<Object>>) create(o.getClass());
我收到類似的錯誤:
java: inconvertible types
required: G<java.lang.Object,Y<java.lang.Object>>
found: G<capture#1 of ? extends java.lang.Object,Y<capture#1 of ? extends java.lang.Object>>
再次,我為零散的信息表示歉意。 我在寫作時正在對此進行分類。
您已經從getClass()
方法傳遞了Class
對象, 該方法返回Class<?>
,這意味着您必須將t
聲明為G<?>
。
當變量的通用類型參數是通配符時,不能使用通用類型參數調用方法。 編譯器不知道通配符實際上是哪個特定類,因此在調用這種方法時不能保證類型安全。 這也是不能在List<?>
上調用add
的相同原因。
要使其編譯,必須使用類文字,以避免使用Class<?>
,並聲明t
不具有通配符。
G<Object> t = create(Object.class);
然后
t.mo(o);
將編譯。
您在這里擁有的是消費者。 但是,以下代碼似乎可以編譯(在Eclipse中)。
public static class G<X, Z extends Y<X>> {
public G(Class<? extends X> c, Class<Z> s) {}
public void m(X x) {}
public static <T, S extends Y<T>> G<T, S> create(Class<? extends T> c) {
Class<S> s = null; // find this via some reflection magic
return new G<T, S>(c, s);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
create(o.getClass()).m(o);
}
}
您正在創建一個G<Object>
,然后將其分配給G<?>
類型的變量。 調用的方法采用通用類型的變量,而<?>
則不接受任何類型。 如果將變量更改為G<Object>
,它將起作用。
由於您指定了G<?>
,因此javac期望找出泛型是什么(它們代表什么類)。 將語句更改為G t = create(o.getClass());
解決錯誤。
capture
錯誤通常意味着編譯器無法找出類...
現在還不清楚您要做什么...也許這些信息將對您有所幫助...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.