假设我们有这 3 个类:
class A { }
class B extends A { }
public class App {
static void f(int i, A a) { }
static void f(float j, B b) { }
static public void main() {
int i = 0;
B b = new B();
App.f(i, b);
}
}
Run Code Online (Sandbox Code Playgroud)
这会产生错误:
class A { }
class B extends A { }
public class App {
static void f(int i, A a) { }
static void f(float j, B b) { }
static public void main() {
int i = 0;
B b = new B();
App.f(i, b);
}
}
Run Code Online (Sandbox Code Playgroud)
f(int, A)既然i是整数,为什么不选择类型?
Swe*_*per 36
由于两个原因,它是模糊的:
\n请注意,f(int, A)重载和f(float, B)重载都可以使用参数来调用(i, b),因为存在从intto的隐式转换和从tofloat的隐式转换。BA
当有不止一种适用方法时会发生什么?Java 应该选择最具体的方法。这在语言规范的\xc2\xa715.12.2.5中进行了描述。事实证明,这些重载之一并不比另一个更具体。
\n\n\n对于使用参数表达式 e1, ..., ek 的调用,如果满足\n以下任一条件,则一种适用的方法 m1 比另一种适用的方法 m2 更具体:
\n\n
\n- \n
m2 是通用的 [...]
\n- \n
m2 不是泛型,m1 和 m2 可通过严格或松散调用应用,其中 m1 具有形参类型 S1, ..., Sn 且 m2\n具有形参类型 T1, ..., Tn,类型 Si 是对于所有 i (1 \xe2\x89\xa4 i \xe2\x89\xa4 n, n = k),参数 ei 比 Ti 更具体。
\n- \n
m2 不是通用的,m1 和 m2 可通过变量 arity 调用应用 [...]
\n
只有第二点适用于 的两个重载f。为了使一个重载比另一个重载更具体,一个重载的每个参数类型必须比另一个重载中相应的参数类型更具体。
\n\n对于任何表达式,如果 S <: T ( \xc2\xa74.10 ) ,则类型 S 比类型 T 更具体。
\n
注意“<:”是子类型关系。B显然是 的子类型A。float实际上是 的超类型(不是子类型!)int。这可以从\xc2\xa74.10.1中列出的直接子类型关系导出。因此,这两个重载都不比另一个重载更具体。
语言规范继续讨论最具体的方法,这并不真正适用于f这里。最后,它说:
\n\n否则,方法调用不明确,并且会发生编译时错误。
\n
static void f(int x) {}\nstatic void f(float x) {}\nRun Code Online (Sandbox Code Playgroud)\n当使用 an 调用时int不会有歧义,因为int重载更加具体。
static void f(int x, B a) {}\nstatic void f(float x, A a) {}\nRun Code Online (Sandbox Code Playgroud)\n当使用参数调用时,类型(int, A)不会含糊,因为(int, B)重载更加具体。
static void f(int x, A a) {}\nstatic void f(float x, A a) {}\nRun Code Online (Sandbox Code Playgroud)\n当使用参数调用时,类型(int, A)不会含糊,因为(int, A)重载更加具体。请注意,子类型关系是自反的(即A是 的子类型A)。