【问题标题】:Instanciate generic Parameter of a class实例化类的通用参数
【发布时间】:2017-03-21 10:40:46
【问题描述】:

我有课

class Holder<SomeType extends AbstractType>{
    SomeType createType(){...}
}

然后在它之外,我打电话

Holder holder = new Holder<MyType>();

我不知道如何实现 createType() 方法。

我尝试了在 StackOverflow 和网络中可以找到的所有内容,但我总是在同一个死胡同中运行: 在运行时,如果我这样做了

TypeVariable typeVariable = getClass().getTypeParameters()[0];
System.err.println("typeVariable "+typeVariable);

我得到的是“SomeType”而不是“MyType”,所以我无法获取适当的构造函数,因为我想使用 Class.forName("MyType") 而不是 Class.forName("SomeType") 导致java.lang.ClassNotFoundException

我使用 SomeType extends AbstractType,所以我知道我所有的 MyTypes 都将具有相同的可用构造函数。

我不能用

ParameterizedType t = (ParameterizedType) MyClass.class.getGenericSuperclass();

因为 Holder 不是任何有用的子类

我可以在我的 Holder 类中做这样的事情,但我正在寻找一种无需在构造函数中传递参数即可使用反射的方法

private final Class<SomeType> type;

public Holder(Class<SomeType> type) {
    this.type = type;
}

尝试我在网上看到的所有各种想法感觉就像我在追逐我的尾巴,所以我想我在这里遗漏了一个明显的元素。

感谢您的帮助!

编辑:我无法像Create instance of generic type in Java? 那样解决它 我不能将类作为 createType(Class) 的参数传递,因为在调用 createType 时我不知道该类(当我不知道我的类型时,此方法应该创建适当类型的子类)孩子们应该是)

【问题讨论】:

  • 由于类型擦除,调用new Holder&lt;MyType&gt;() 的泛型类型在运行时是未知的,因此您所能做的就是以某种方式传递该信息,例如通过传入类型类。或者,您可以创建子类,例如class MyTypeHolder extends Holder&lt;MyType&gt; 在这种情况下你可以use reflection to extract the generic type
  • 或许你可以将createType的声明改为 T createType(Class extends AbstractType> clz) {} 然后像SomeType sType = (SomeType)holder.createType(MyType.班级);这样,Holder 类就不必是通用的。
  • 你指的是.class.newInstance()吗?
  • 谢谢 Thomas,我尝试了我的方法来摆脱 20 多个 MyType1Holder、MyType2Holder... 我想我只需要在 Holder 的构造函数中传递类以避免类型擦除。我会回复而不是评论,我可以投票赞成你的答案;)

标签: java generics reflection


【解决方案1】:

就像 Thomas 在 cmets 中所说,Java 使用类型擦除。这意味着填写SomeType 的具体类型不会隐式传递给Holder。但是要实例化一个类,您需要该类型信息。因此,您必须将该信息显式传递给Holder。有几种方法可以做到这一点,您已经找到了其中一种。在构造它时将Class 对象传递给Holder

Java 8 引入了方法引用,也允许您引用构造函数:

Function<String, MyType> cons = MyType::new;

这将创建函数接口 Function 的一个实例,该实例具有一个方法 apply,该方法接受一个 String 并返回一个 MyType

然后您可以将此函子传递给Holder 的构造函数,并将其保存以在createType 中使用:

class Holder<SomeType extends AbstractType>{
    private final Function<String, SomeType> cons;

    public Holder(Function<String, SomeType> cons) {
        this.cons = cons;
        ...
    }

    SomeType createType() {
        return cons.apply("SomeString");
    }
}

与以相同方式使用Class 相比,这样做的优点是您在编译时知道构造函数的签名,并且不会抛出异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多