Java泛型益智游戏与通用静态工厂

时间:2014-03-12 20:15:15

标签: java generics

我最近开始为一个项目编写一个通用的对象映射器,并遇到了一些我不太了解的东西。鉴于以下内容:

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>>

我再一次为零碎的信息道歉。在我写作的时候,我正在对此进行整理。

4 个答案:

答案 0 :(得分:2)

您已通过the getClass() methodClass对象,该对象返回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错误通常意味着编译器无法弄清楚类...

你还不清楚自己要做什么......或许这些信息可以帮助你更多......