【问题标题】:Accessing type arguments from generic types used in typebounds从类型绑定中使用的泛型类型访问类型参数
【发布时间】:2012-01-01 09:31:55
【问题描述】:

我发现泛型存在以下问题。考虑通用接口

public interface A<X> {
    X get();
    void doStuff(X x);
}

现在,让我们假设以下方法定义:

public <T extends A<?>> void foo(T t) {
    bar(t);
}

由于通配符的原因,get() 的返回类型的类型信息不足。因此,我必须委托另一个方法将这个通配符“绑定”到一个新的类型变量:

private <X> void bar(A<X> t) {
    X x = t.get();
    t.doStuff(x);
}

不允许调用foo中的bar(),编译器输出如下错误信息:

类型测试中的方法bar(A)不适用于参数(T)

但是,如果我将方法 foo() 更改为

public <T extends A<?>> void foo(T t) {
    A<?> u = t; // No explicit cast required, no "unchecked" warning!
    bar(u);
}

它有效。为什么?这是编译器错误吗?任何有关这方面的 cmet 将不胜感激。

注意事项:

  • 我之所以不简单地将方法 foo 声明为 void foo(A) 是因为我实际上使用的是上限类型边界交点 (&)。
  • 我之所以不在 foo() 中将 X 声明为类型变量,是因为我实际上在类级别存在问题,并且不想不必要地增加此类的类型参数的数量。

【问题讨论】:

  • 您是否使用 -Xlint 编译器标志?如果没有,请尝试使用它进行编译
  • 我同意@kan。 java编译器确实编译了这个。我用的是 1.6.0_27。 Eclipse 确实给出了你给出的确切错误,所以也许你正在使用它?
  • 使用@kan 的示例创建了 eclipse 错误:bugs.eclipse.org/bugs/show_bug.cgi?id=364200
  • 不使用 javac 1.7.0 编译。

标签: java generics


【解决方案1】:

我已经检查了代码:

public class Test
{
    public interface A<X> {
        X get();
        void doStuff(X x);
    }
    public <T extends A<?>> void foo(T t) {
        bar(t);
    }

    private <X> void bar(A<X> t) {
        X x = t.get();
        t.doStuff(x);
    }
}

它有效。 javac 1.6.0_22。你哪里有错误?还是我使用其他代码?

【讨论】:

  • 谢谢,我会在星期一在我工作的机器上检查它,我不知道我在那里使用的是哪个 javac 版本。我只是在家里测试了它,它没有使用 javac 1.6.0_11 编译...
  • 顺便说一句,错误只是“bar(Test.A) in Test 不能应用于 (T)”,标记指向 bar() 调用。
【解决方案2】:

代码:

public class Test
{
    public interface A<X> {
        X get();
        void doStuff(X x);
    }
    public <T extends A<?>> void foo(T t) {
        bar(t);
    }

    private <X> void bar(A<X> t) {
        X x = t.get();
        t.doStuff(x);
    }
}

仅针对 Java 1.6 的选定版本进行编译。这个bug 被记录为日食,但被 Srikanth Sankaran 拒绝并给出以下解释:

我相信 eclipse 编译器的行为是正确的并且匹配 JDK5 和 JDK7(最新)。看起来JDK6的行为是 回归已被修复。

基本上,这里是对这里发生的事情的简要说明:

鉴于 bar(t) 给出的通用方法 bar 和调用站点, 推理算法没有约束来推断类型 类型变量 X。所以在考虑了参数和 预期返回类型等,X 仍未解决且符合规范 被解析为发布的下限 - 即 X 被推断为 对象和方法变为 void bar(A) t);由于实际 参数不能转换为形参,推断 方法必须被拒绝,使我们没有适用的候选人。 因此,呼叫必须被拒绝。

调用bar((A)t)的原因;成功是在这种情况下 X 被推断为“capture#1-of ?”和通用方法 使用此替换进行参数化后,参数兼容性成立的 void bar(A)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-09
    • 2021-05-11
    • 2011-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多