当前位置: 首页 > 知识库问答 >
问题:

使用在运行时确定的类调用泛型方法

马奇略
2023-03-14

我正在尝试使用jersey 2/HK2自动绑定带有特定注释的工厂类。因此,我在运行时从泛型接口获取所提供的类型,然后尝试将工厂绑定到此类型。将工厂绑定到类的方法如下所示:

protected void bindResourceFactory(Class<? extends Factory<?>> factory) {
  Class<?> providedClass = getProvidedClass(factory);
  bindFactory(factory).to(providedClass).in(Singleton.class);
}

HK2提供的bindfactoy方法定义如下:

public <T> ServiceBindingBuilder<T> bindFactory(Class<? extends Factory<T>> factoryType) {
    return resetBuilder(AbstractBindingBuilder.<T>createFactoryBinder(factoryType, null));
}

当我用Eclipse构建所有东西时,这似乎工作得很好。然而,当我使用maven构建项目时,我会得到以下构建错误:

[ERROR] /Users/jan/Documents/Workspace/jersey-test/bind/ResourceFactoryBinder.java:[32,5] no suitable method found for bindFactory(java.lang.Class<capture#1 of ? extends org.glassfish.hk2.api.Factory<?>>)
[ERROR]     method org.glassfish.hk2.utilities.binding.AbstractBinder.<T>bindFactory(java.lang.Class<? extends org.glassfish.hk2.api.Factory<T>>,java.lang.Class<? extends java.lang.annotation.Annotation>) is not applicable
[ERROR]       (cannot infer type-variable(s) T
[ERROR]         (actual and formal argument lists differ in length))
[ERROR]     method org.glassfish.hk2.utilities.binding.AbstractBinder.<T>bindFactory(java.lang.Class<? extends org.glassfish.hk2.api.Factory<T>>) is not applicable
[ERROR]       (cannot infer type-variable(s) T
[ERROR]         (argument mismatch; java.lang.Class<capture#1 of ? extends org.glassfish.hk2.api.Factory<?>> cannot be converted to java.lang.Class<? extends org.glassfish.hk2.api.Factory<T>>))
[ERROR]     method org.glassfish.hk2.utilities.binding.AbstractBinder.<T>bindFactory(org.glassfish.hk2.api.Factory<T>) is not applicable
[ERROR]       (cannot infer type-variable(s) T
[ERROR]         (argument mismatch; java.lang.Class<capture#1 of ? extends org.glassfish.hk2.api.Factory<?>> cannot be converted to org.glassfish.hk2.api.Factory<T>))

共有1个答案

和魁
2023-03-14

发生此错误的原因是编译器没有捕获转换类<? 扩展 ;工厂<?>>中的“内部”通配符(工厂<?>)。(根据规范,“捕获转换不是递归应用的”。)

用一个不同的(但与所涉及的类型类似的)示例来解释为什么会发生这种情况会更容易。假设我们有一个列表的任何类型的列表:

List<List<?>> lists = ...;

现在假设我们有一个处理列表的列表的方法,但假设列表都具有相同的类型:

<T> void process(List<List<T>> lists) {
    // and at this point we should note that List<T>
    // allows us to add elements to the lists, so we
    // could do something like this:

    if (!lists.isEmpty()) {
        List<T> list0 = lists.get(0);

        for (int i = 1; i < lists.size(); ++i)
            list0.addAll(lists.get(i));
    }
}
List<Double> doubles = new ArrayList<>();
Collections.addAll(doubles, 0.0, 1.0, 2.0);

List<String> strings = new ArrayList<>();
Collections.addAll(strings, "X", "Y", "Z");

List<List<?>> lists = new ArrayList<>();
Collections.addAll(lists, strings, doubles);

在这种情况下,更明显的是,我们不能将列表 传递给接受列表 > 的过程方法。编译器实际实现这一点的方式是,它不会捕获某个类型变量t的“内部”通配符。

问题中的代码没有编译,原因非常相似。由于class上的类型参数主要与与构造函数相关的方法相关(特别是newInstance方法),我们可以使用supplier来展示一个更类似的示例:

static void example(Supplier<? extends Factory<?>> s) {
    capture(s);
}
static <T> void capture(Supplier<? extends Factory<T>> s) {
    Factory<T> a = s.get();
    Factory<T> b = s.get();
    // remember, a and b are supposed to have the same type
    T obj = a.provide();
    b.dispose(obj);
}

问题是,由于我们的供应商最初可能是供应商 ,所以它没有理由不从一个调用返回工厂 而从另一个调用返回工厂 。因此,我们不能将供应商 > 捕获到供应商 > class.newInstance将始终返回完全相同类型的对象,但编译器并不知道这一点。

我认为Eclipse的编译器在这种情况下可能错误地编译了问题中的代码。

如果您想强制编译,您可以像注释中的用户所建议的那样使用未经检查的强制转换,但我对所涉及的类了解不足,无法说明其结果是否确实正确。上面的两个代码示例展示了这样做可能会发生严重错误(原则上),但class有时是一种特殊情况。

更合适的修复方法是在bindresourceFactory声明一个类型变量,这样它也需要一个类<? 扩展 ;Factory > ,但我不知道这对于您调用方法的方式是否有效。

 类似资料:
  • 问题内容: 给定具有以下结构的类。我试图确定由泛型方法的调用者分配的参数T的类型。 在C#中,我将使用“ default(T)”或“ typeof(T)”,但我试图在Java中执行此操作。谁知道/如何做?我真的不需要实例,我只需要Class定义。 问题答案: 你不能那样做。您可以做的是使方法签名如下: 然后,您可以使用给定的类检查类型。

  • 问题内容: 没有静态成员可以使用类型参数,但是可以使用泛型类型参数调用静态成员吗​​?例如:- 这里的add()是一个静态方法。 在类似的主题上也有一些C#问题和答案,但是我不太确定如何在Java中使用它。 问题答案: 不,如果A是泛型类型,则无法执行。(Bozho对fast的回答是:),可能认为A是具体类型。 可行的方法如下。 但这可能不是您想要的。 阅读您的评论后,听起来您真正想要做的是: 您

  • 问题内容: 我注意到使用泛型和lambda重载方法的行为很奇怪。这个课程效果很好: 没有模棱两可的方法调用。但是,将其更改为此将使第二个调用不明确: 怎么会这样?为什么添加另一个参数会导致方法解析不明确?为什么在第一个示例中却能分辨出Supplier和Object之间的区别,而在第二个示例中却不能呢? 编辑:这是使用1.8.0_121。这是完整的错误消息: 问题答案: 如果我对JSE for Ja

  • 我有一个有界泛型类,我们称之为泛型,它的参数T扩展了抽象类abstract: 泛型类: 抽象类 泛型类中T引用的类 当尝试引用方法 getMap() 时,该方法来自 T 边界内的类(并且根据抽象类定义,T 的所有可能实例都将具有该方法),我收到以下错误: 不能从静态上下文引用非静态方法getMap() 然而,任何地方都没有静态关键字。我错过了什么?? 谢谢!

  • 问题内容: 我想知道用这样的签名调用静态方法的正确方法是什么: 由于某种原因,我很想这样称呼它: 但是除非我将其更改为:否则它不会编译: 我只是想知道为什么它不需要右侧的提示。而是给了我编译错误。它说它期望在右侧的提示后加上分号。第二个方法是调用该方法的正确方法吗?有人可以给我一些启示吗? 问题答案: 如图所示这里,要调用的方法的方法是: 该方法所在的类的名称在哪里。

  • 我一直在尝试泛型,很快我就遇到了一些我无法解释的事情 例如: 我不明白