多个最大特定方法的示例,这些方法不会导致编译时错误

joh*_*ell 7 java generics overloading method-invocation

我需要深入研究Java中方法调用的细节,在阅读Java语言规范(Java SE 12版)中的选择最特定的方法 ”一节时,我发现(1)在调用期间,多个方法可以是最大程度的特定,并且该(2)具有多个最大的具体方法并不总是导致编译时错误。

我能够想到一个示例,其中两个方法都是最大特定的:

interface A {}

interface B {}

class C implements A, B {
    <T extends A> void foo(T t) {};
    <T extends B> void foo(T t) {};
}

class Main {
    public static void main(String[] args) {
        new C().<C>foo(null);
    }
}
Run Code Online (Sandbox Code Playgroud)

此示例导致编译时错误: error: reference to foo is ambiguous

这对我来说很有意义,但是对我来说没有意义的是,当存在多个最大特定方法时,并且不会导致编译时错误。

的部分选择最具体的方法Java语言规范(爪哇SE 12版)中提到两种情况,其中,编译器能够选择当存在多个最大特定方法的方法:

  • 如果所有最大特定方法都具有等效的签名(第8.4.2节),并且恰好是最大特定方法之一是具体的(即既不是抽象方法也不是默认方法),则它是最特定的方法。

  • 否则,如果所有最大特定方法都具有等效的签名,并且所有最大特定方法都是抽象或默认方法,并且这些方法的声明具有相同的擦除参数类型,则根据该方法,至少应选择一个最大特定方法。遵循以下规则,则可以从首选的最大特定方法子集中任意选择最特定的方法。然后,最具体的方法被认为是抽象的。

首先,如何调用is方法abstract?为什么abstract曾经考虑将方法用于方法调用?

其次,有人可以针对这两种情况中的每种情况提供一个不会导致编译时错误的示例吗?

And*_*lko 2

\n

我发现(1)在调用期间多个方法可以具有相同的签名,并且(2)具有相同签名的多个方法并不总是导致编译时错误。

\n
\n\n

一个类不能包含具有相同签名的两个方法。

\n\n
\n

8.4.2. 方法签名

\n\n

如果两个方法或构造函数 M 和 N 具有相同的名称、相同的类型参数(如果有)(\xc2\xa78.4.4),并且在将 N 的形式参数类型调整为参数M的类型,与形参类型相同。

\n\n

方法 m1 的签名是方法 m2 签名的子签名,如果:

\n\n
    \n
  • m2 与 m1 具有相同的签名,或者

  • \n
  • m1 的签名与 m2 签名的擦除(\xc2\xa74.6)相同。

  • \n
\n\n

两个方法签名 m1 和 m2 是覆盖等效的,当且仅当 m1 是 m2 的子签名或 m2 是 m1 的子签名。

\n\n

在类中声明两个具有等效重写签名的方法是一个编译时错误。

\n
\n\n

在您的示例中,有两种方法具有两个不同的签名。它可以编译并正常工作,除非您引入像new C().<C>foo(null);. 编译时错误“对 foo 的引用不明确”并不意味着<T extends A> void foo(T t)<T extends B> void foo(T t)不能共存。他们实际上可以而且确实这样做了。

\n\n

正如评论中提到的,类型擦除后,方法将如下所示

\n\n
 void foo(A t);\n void foo(B t);\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

如何调用抽象方法?为什么要考虑将抽象方法用于方法调用?

\n
\n\n

在抽象上下文中(例如在抽象类中)调用抽象方法是绝对没问题的。

\n\n
\n

有人可以为这两种情况提供一个不会导致编译时错误的示例吗?

\n
\n\n

我可以想到一个例子,其中有两个“具有覆盖等效签名的最大特定方法”用于调用new C().foo();,并且它已成功解析为有利于A\ 的方法。

\n\n
abstract class A {\n    public void foo() {\n        System.out.println("a");\n    }\n}\ninterface B {\n    default void foo() {\n        System.out.println("b");\n    }\n}\nclass C extends A implements B {\n    public static void main(String[] args) {\n        new C().foo();  // prints a\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n