我最近开始为一个项目编写一个通用的对象映射器,并遇到了一些我不太了解的东西。鉴于以下内容:
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。
编辑:
这是不一个学术问题。我试图将一个映射器从hibernate对象编写到相应的DTO,以便在REST层中传递。假设对于每个ORM对象Foo
,可能存在具有构造函数的类FooDTO
,该构造函数将Foo
的实例作为参数。将Foo
映射到FooDTO
的通用类将封装此假设,并在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>>
我再一次为零碎的信息道歉。在我写作的时候,我正在对此进行整理。
答案 0 :(得分:2)
您已通过the getClass()
method的Class
对象,该对象返回Class<?>
,这意味着您必须将t
声明为G<?>
。< / p>
当变量的泛型类型参数是通配符时,不能使用泛型类型参数调用方法。编译器并不知道通配符确实属于哪个特定类,因此在调用此方法时无法保证类型安全。这与add
无法调用List<?>
的原因相同。
要编译它,必须使用类文字,以避免使用Class<?>
,并声明t
不要使用通配符。
G<Object> t = create(Object.class);
然后
t.mo(o);
将编译。
答案 1 :(得分:1)
你在这里有一个消费者。但是,以下似乎是编译的(在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);
}
}
答案 2 :(得分:0)
您正在创建G<Object>
,然后将其分配给G<?>
类型的变量。调用的方法采用泛型类型的变量,这不会占用<?>
的任何内容。如果您将变量更改为G<Object>
,它将起作用。
答案 3 :(得分:-1)
由于您正在指定G<?>
,因此javac希望弄清楚泛型是什么(它们代表什么类)。将语句更改为G t = create(o.getClass());
可修复错误。
capture
错误通常意味着编译器无法弄清楚类...
你还不清楚自己要做什么......或许这些信息可以帮助你更多......