为通用参数保持关联 class

Keeping associated class for a generic parameter

我有一些带有通用参数的 class,出于各种原因,我需要与该参数关联的具体 class,所以我想接受它作为构造函数的一部分,例如:

public class Foo<T> {
    private final Class<T> clazz;
    public Foo(Class<T> clazz) {
        this.clazz = clazz;
    }
}

我还有一些其他的 class,我想用它来构造它,它也被参数化了,例如:

public class MyObj<T> { /* stuff */ }

当我尝试用 MyObj 创建 Foo<T> 时,我似乎无法计算出参数来编译。例如这失败了:

Foo<MyObj<?>> foo = new Foo<MyObj<?>>(MyObj.class);

编译时错误如:

The constructor Foo<MyObj<?>>(Class<MyObj>) is undefined

同样,当我为 MyObj 提供具体类型时,事情仍然失败:

Foo<MyObj<String>> foo = new Foo<MyObj<String>>(MyObj.class);

编译时错误如:

The constructor Foo<MyObj<String>>(Class<MyObj>) is undefined

我怀疑 Foo 的构造函数参数在我对 Foo 的定义中或在我对构造函数的调用中不正确,但我不确定如何修改类型参数。

我该如何解决这个问题?

Class 不能表示参数化类型。同一个 Class 对象将 MyObj<String> 表示为 MyObj<Integer>(或者更确切地说,没有 MyObj<String> 类型的对象,只有 MyObj 类型的对象,泛型是一个编译时特性,它们不在运行时定义对象。

如果你只是有一个非通用的

class MyObj {}

你可以简单地做

Foo<MyObj> foo = new Foo<>(MyObj.class);

但是由于您的类型是泛型的,并且您似乎想要维护其类型参数的类型,因此您需要更进一步。您需要类型标记。

Guava 提供了TypeTokenclass你可以使用。您必须将 Foo 更改为

class Foo<T> {
    final Type type;

    public Foo(Type type) {
        this.type = type;
    }
}

然后

Foo<MyObj<String>> foo = new Foo<MyObj<String>>(new TypeToken<MyObj<String>>() {}.getType());

现在,如果您打印 type,您将看到

com.example.MyObj<java.lang.String>

如果将其转换为 ParameterizedType,则可以检索其参数化。

但是请注意,您无法在此处获得类型安全。你可能不小心写了

Foo<MyObj<String>> foo = new Foo<MyObj<String>>(new TypeToken<MyObj<Integer>>() {}.getType());

编译成功。

我会这样做:

  Foo<MyObj> foo = new Foo<MyObj>(MyObj.class);

如果我真的知道你试图解决的更高层次的问题是什么,我可以提供更好的建议。但我所要做的就是 "Foo" 和 "MyObj"