11

我想知道为什么这段代码编译成功?

源代码:

abstract class A<K extends Number>
{
    public abstract <M> A<? super M> useMe(A<? super M> k);
}

编译成功

它是如何工作的,为什么会编译?M是任意类型,为什么可以使用呢?应该是:<M extends Number>?这不会编译:

abstract class A<K extends Number>
{
    public abstract <M> A<? super M> useMe(A<M> k);
}

错误信息:

类型参数 M 不在类型变量 K 的范围内,其中 M、K 是类型变量: M 扩展在方法 useMe(A) 中声明的对象 K 扩展在类 A 中声明的数字

有什么区别?

4

4 回答 4

5

此编译器行为已在此 Eclipse 错误中进行了讨论。最初,Eclipse 编译器对您的示例中的表达式做了错误,而 javac 没有。虽然我还没有直接搜索 JLS,但共识似乎是规范中没有任何内容需要根据类型参数范围检查下界通配符。在这种情况下,最终由调用者分配满足约束的类型(正如 Stephan Herrmann 在该帖子中所推测的那样)。

于 2013-12-24T00:13:24.883 回答
2

这是一段令人惊讶的毫无意义的代码。

它所说的只是该类A采用了一个泛型类型KaNumber并且有一个方法useMe返回一个A<T>带有一些毫无意义的额外限制的方法(显然T是 a除外)。Number

这是一个实现,以显示糖所说的很少:

abstract class A<K extends Number> {
    public abstract <M> A<? super M> useMe(A<? super M> k);
}

class B extends A<Number> {

    @Override
    public <M> A<? super M> useMe(A<? super M> k) {
        // Not much more you can do here but this.
        return k;
    }

}

这些? super M东西只是毫无意义的gobbledegook - 编译器可以从中派生出来的只是传递给它的参数和返回的结果都必须是特定未命名类的超类。

泛型可以在编译时轻松检测编码错误。像这样使用 mumbo-jumbo 只是误导性的混淆。

于 2013-12-24T00:11:34.293 回答
1

添加<M extends Number>到第一个示例不会添加编译器关心的任何内容。请记住,如果我们说“M 是 Number 的子类型”和“该类型是 M 的超类型”,您说的是“类型是 M 的超类型”,我们实际上并不是说该类型是否是的子类型数字。

举个更好的例子, have MbeInteger和变量 be 的类型A<Object>。虽然这显然行不通,但它正确地满足了该功能的所有要求。

由于无法修复函数定义,它只是让它通过并假设调用站点会发现问题。

于 2013-12-23T23:36:55.580 回答
-1

你的问题有两个部分:

第 1 部分:什么是<M>

方法上泛型参数的存在使其成为“类型化方法”,这意味着该方法具有由调用者确定的泛型类型,通常通过推理。它可能是有界的。如果类也有类型并且方法是实例方法,那么这两种类型是不相关的。

第2部分:

泛型类型必须完全匹配。原因归结为 ifB是 的子类型ASomeClass<T extends B>不是 的子类型SomeClass<T extends A>,更具体地说,SomeClass<A>不是 的子类型SomeClass<? super A>

于 2013-12-24T05:28:46.320 回答