【问题标题】:Ambiguous overloaded generic method with wildcard in parameter参数中带有通配符的模棱两可的重载泛型方法
【发布时间】:2015-03-23 13:39:14
【问题描述】:

鉴于以下声明

interface Base<A> { }

interface Special<A,B> extends Base<A> { }

<T> void foo(Base<T> b) {}

<T> void foo(Special<?,T> s) {}

为什么我会收到以下代码的编译错误:

Special<String, Integer> s = null;
foo(s); // error: reference to foo is ambiguous

顺便说一句,问题可以通过将第二种方法的声明更改为

<T,X> void foo(Special<X,T> s) {}

【问题讨论】:

  • PS:是的,有很多关于模棱两可的重载泛型方法的问题,但我找不到适合这个问题的问题
  • 这也可以用&lt;T&gt; void foo(Special&lt;Object,T&gt; s) {}修复。
  • @sp00m 已修复,但我不能再用Special&lt;String, Integer&gt; 调用第二种方法。该调用将明确引用Base 版本。

标签: java generics overloading overload-resolution


【解决方案1】:

首先,一个非常有趣的问题。

没有泛型

考虑以下代码:

interface NoGenericsBase { }

interface NoGenericsSpecial extends NoGenericsBase { }

interface NoGenericsSuperSpecial extends NoGenericsSpecial { }

void foo(NoGenericsBase b) {
    System.out.println("Feel tha base");
}

void foo(NoGenericsSpecial s) {
    System.out.println("Special delivery");
}

我们一直被告知编译器会选择最具体的方法。事实上,如果您调用foo((NoGenericsSuperSpecial) null),上述代码将打印以下内容:

特快专递

到目前为止,一切都很好。

泛型

现在,让我们测试一些泛型行为:

interface Base<T> { }

interface Special<T> extends Base<T> { }

void foo(Base<? extends Number> b) {
    System.out.println("Feel tha base");
}

void foo(Special<? extends Number> s) {
    System.out.println("Special delivery");
}

public static void main(String[] args) {
    Special<Integer> v = null;
    new Main().foo(v);
}

此代码编译。编译器找到两个匹配项——Base&lt;? extends Number&gt;Special&lt;? extends Number&gt; 都适用——但编译器能够找出哪个是最具体的:它将选择 void foo(Special&lt;? extends Number&gt;),因为未绑定通配符的两个捕获是相等的。

但是让我们重写foo(Base&lt;...&gt;) 方法,其余的保持不变:

void foo(Base<? extends Integer> b) {
    System.out.println("Feel tha base");
}

现在出现以下错误:

对 foo 的引用不明确
方法foo(Base&lt;? extends Integer&gt;) 和方法foo(Special&lt;? extends Number&gt;) 都匹配

在找出最具体的类型匹配之前,编译器会处理类型变量。显然,编译器无法确定是 &lt;? extends Number&gt; 还是 &lt;? extends Integer&gt; 应用,不管变量本身的类型BaseSpecial)。

似乎变量类型处理先于选择与继承有关的方法签名。

一个人(或至少我自己)应该期望编译器选择foo(Special&lt;? extends Number&gt;),但事实并非如此。

原因

我不知道编译器是否无法选择最具体的泛型,或者它没有配置为这样做。

有关详细信息,请参阅 Java 语言规范 § 18.5§ 4.5.1

让我花点时间阅读更多泛型,也许我们可以弄清楚...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    相关资源
    最近更新 更多