确定在编译时调用哪个方法签名的规则在语言规范。特别重要的是关于选择的部分最具体的方法。以下是与您的问题相关的部分:
如果多个成员方法既可访问又适用于方法调用,则需要选择一个成员方法来为运行时方法分派提供描述符。 Java 编程语言使用以下规则:最具体的方法被选择。
...
One applicable method m1
is more specific than another applicable method m2
, for an invocation with argument expressions e1
, ..., ek
, if any of the following are true:
-
m2
is generic, and m1
is inferred to be more specific than m2
for argument expressions e1
, ..., ek
by §18.5.4.
-
m2
is not generic, and m1
and m2
are applicable by strict or loose invocation, and where m1
has formal parameter types S1, ..., Sn and m2
has formal parameter types T1, ..., Tn, the type Si is more specific than Ti for argument ei
for all i (1 ≤ i ≤ n, n = k).
...
S型是更具体如果 S <: t>
在这种情况下,Integer
比更具体Number
因为Integer
延伸Number
,因此每当编译器检测到对foo
需要一个变量declared类型的Integer
,它将添加一个调用foo(Integer)
.
有关与第二种方法通用相关的第一个条件的更多信息,请参见本节。这有点冗长,但我认为重要的部分是:
当测试一种适用的方法时更具体与另一个方法(§15.12.2.5)相比,如果第二个方法是通用的,则有必要测试是否可以推断出第二个方法的类型参数的某些实例化,以使第一个方法比第二个方法更具体。
...
Let m1
be the first method and m2
be the second method. Where m2
has type parameters P1, ..., Pp, let α1, ..., αp be inference variables, and let θ be the substitution [P1:=α1, ..., Pp:=αp].
...
The process to determine if m1
is more specific than m2
is as follows:
...
If Ti is a proper type, the result is true if Si is more specific than Ti for ei (§15.12.2.5), and false otherwise. (Note that Si is always a proper type.)
这基本上意味着foo(Number)
and foo(Integer)
两者都比foo(T)
因为编译器可以推断出泛型方法的至少一种类型(例如Number
本身)使得foo(Number)
and foo(Integer)
更具体(这是因为Integer <: Number
and Number <: Number
) .
这也意味着在您的代码中foo(T)
仅适用于传递 a 的调用(并且本质上是最具体的方法,因为它是唯一适用的方法)String
.