[英]Why do I get an ambiguity error in this code?
Let's say we have these 3 classes:假设我们有这 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);
}
}
This produces the error:这会产生错误:
App.java:11: error: reference to f is ambiguous
App.f(i, b);
^
both method f(int,A) in App and method f(float,B) in App match
1 error
Why does it not choose the type f(int, A)
since i
is an integer?为什么它不选择
f(int, A)
类型,因为i
是 integer?
It is ambiguous because of two reasons:之所以模棱两可,原因有二:
Notice that both the f(int, A)
overload and the f(float, B)
overload can be called with the parameters (i, b)
, since there is an implicit conversion from int
to float
, and an implicit conversion from B
to A
.请注意,
f(int, A)
重载和f(float, B)
重载都可以使用参数(i, b)
调用,因为存在从int
到float
的隐式转换,以及从B
到的隐式转换A
。
What happens when there are more than one applicable method?当有不止一种适用的方法时会发生什么? Java is supposed to choose the most specific method.
Java应该选择最具体的方法。 This is described in §15.12.2.5 of the language spec.
这在语言规范的§15.12.2.5中有描述。 It turns out that it is not the case that one of these overloads are more specific than the other.
事实证明,这些重载中的一个并非比另一个更具体。
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:
一个适用的方法 m1 比另一个适用的方法 m2 更具体,用于使用参数表达式 e1、...、ek 的调用,如果以下任何一项为真:
m2 is generic [...]
m2 是通用的 [...]
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).
m2 不是泛型的,m1 和 m2 可以通过严格或松散调用来应用,其中 m1 有形参类型 S1,...,Sn,m2 有形参类型 T1,...,Tn,类型 Si 更多对于所有 i (1 ≤ i ≤ n, n = k),参数 ei 比 Ti 更具体。
m2 is not generic, and m1 and m2 are applicable by variable arity invocation [...]
m2 不是通用的,并且 m1 和 m2 可通过变量 arity 调用应用 [...]
Only the second point applies to the two overloads of f
.只有第二点适用于
f
的两个重载。 For one of the overloads to be more specific than the other, every parameter type of one overload has to be more specific than the corresponding parameter type in the other overload.为了使其中一个重载比另一个更具体,一个重载的每个参数类型都必须比另一个重载中的相应参数类型更具体。
A type S is more specific than a type T for any expression if S <: T ( §4.10 ).
对于任何表达式,如果 S <: T ( §4.10 ),类型 S 比类型 T 更具体。
Note that"<:" is the subtyping relationship.注意“<:”是子类型关系。
B
is clearly a subtype of A
. B
显然是A
的子类型。 float
is actually a supertype (not subtype!) of int
. float
实际上是int
的超类型(不是子类型!)。 This can be derived from the direct subtyping relations listed in §4.10.1 .这可以从§4.10.1中列出的直接子类型关系推导出来。 Therefore, neither of the overloads is more specific than the other.
因此,没有一个重载比另一个更具体。
The language spec goes on to talk about maximally specific methods, which doesn't really apply to f
here.语言规范继续讨论最大限度地具体的方法,这并不真正适用于
f
这里。 Finally, it says:最后,它说:
Otherwise, the method invocation is ambiguous, and a compile-time error occurs.
否则,方法调用不明确,出现编译时错误。
static void f(int x) {}
static void f(float x) {}
when called with an int
are not ambiguous because the int
overload is more specific.当用
int
调用时并不模棱两可,因为int
重载更具体。
static void f(int x, B a) {}
static void f(float x, A a) {}
when called with argument types (int, A)
are not ambiguous because the (int, B)
overload is more specific.当使用参数类型
(int, A)
调用时,它并没有歧义,因为(int, B)
重载更具体。
static void f(int x, A a) {}
static void f(float x, A a) {}
when called with argument types (int, A)
are not ambiguous because the (int, A)
overload is more specific.当使用参数类型
(int, A)
调用时,它并没有歧义,因为(int, A)
重载更具体。 Note that the subtyping relationship is reflexive (ie A
is a subtype of A
).请注意,子类型关系是自反的(即
A
是A
的子类型)。
Note that for calling an overloaded method in java:请注意,在 java 中调用重载方法:
Priority Order for Primitive types:原始类型的优先顺序:
Same type > Auto Widening > Boxing > Upcasting(Parent Class) > Super Class
相同类型 > 自动加宽 > 拳击 > 向上投射(父类) > Super Class
Priority Order for Reference types:参考类型的优先顺序:
Same type > Upcasting(Parent Class) > Super Class > Unboxing
相同类型 > Upcasting(父类) > Super Class > 拆箱
Explanation:解释:
// you have here a method who accept an int = same Type
// f(int i, A a) { } and this method can accept the other parameter
// because B is a subclass of A
int i = 0;
// But You have a method who accept a B reference = same Type
// f(float j, B b) { } and this method can accept the other parameter
// because float is actually a supertype of int as mentionned by Sweeper
B b = new B();
// So calling the method with an int and a B reference
// will confuse the compiler because both of the two methods
// can accept the other parameter
App.f(i, b);
Two things:两件事情:
Type widening : float
is "wider" type than int
therefore passed int
value can be easily packed into bigger float
box. 类型扩大:
float
是比int
更“宽”的类型,因此传递的int
值可以很容易地打包到更大的float
框中。 It will not work in case, when we would like to "pack" float
into int
, as we can potentially lost floating point.如果我们想将
float
“打包”到int
中,它将不起作用,因为我们可能会丢失浮点。 In provided case, having an int
we can potentially pass it two both functions.在提供的情况下,拥有一个
int
我们可以潜在地将两个函数都传递给它。
fFloat(float f){}
int intValue = 221;
fFloat(intValue); // inside f, intValue is treated as 221.0
fInt(int i){}
float floatVal = 221.221;
fInt(floatVal); // what should compiler do with remaining .221 part?
Inheritance : A
is a base class, while B
is one of subclasses of A. So, when we declare method parameter as a base class, we can provide there both base class and its instance (but we will be able to use B b
instance inside f(int i, A a)
like type A
. Hence, we can pass B b = new B();
to both methods as well. Inheritance :
A
is a base class, while B
is one of subclasses of A. So, when we declare method parameter as a base class, we can provide there both base class and its instance (but we will be able to use B b
instance在f(int i, A a)
内部,类似于A
类型。因此,我们也可以将B b = new B();
传递给这两种方法。
class A {
public void f() {}
}
class B extends A {
public void g() {}
}
fA(A a){}
B bInst = new B();
fA(bInst); // you can refer only to f() method, not g()
fB(B b){}
A aInst = new A();
fB(aInst); // you cannot do this, as subclass can have some additional
// stuff, that superclass does not have
//but even
A aInstBImpl = new B();
fB(aInstBImpl); // will not work without explicit casting as it is
// kind of A instance with B implementation - here polymorphism comes into action
Since all 2 parameters (from 2 possible) can suit to both methods without any explicit "action taken", the ambiguity error arises.由于所有 2 个参数(从 2 个可能)都可以适用于这两种方法,而无需任何明确的“采取行动”,因此会出现歧义错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.