[英]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.