我试图更好地掌握功能重载。
我是这个测试程序(原谅我的C启发Java)。
public class Test {
static void f(int x, double y)
{
System.out.printf("%d, %f",x,y);
}
static void f(double x, int y)
{
System.out.printf("%f, %d", x, y);
}
public static void main(String args[]) {
f(1, 2);
}
}
现在,如果我打电话,
f(1, 2);
存在编译器错误*reference to f is ambiguous*
为什么会出现这个错误?我们不打电话给f(int, int)
吗?但是没有声明这样的方法。我期待"找不到适合f"相反,但我没有得到一个,为什么?
答案 0 :(得分:12)
int
在所有这些语言中都可转换为double
,因此如果只有一个可用,则很容易:转换需要转换的值到double
,然后调用方法。
但是在这种情况下,两个方法都是“有效的”,因为每个方法都可以自己处理 - 但两者都不比另一个“更好”,因为在每种情况下,一个参数只需要身份int
到int
转换,另一个需要int
到double
转换。因此,在Java和C#中,它都是模糊的,并且会因编译时错误而失败。我想象这也是它在C ++中的作用,但我不确定。在Java和C#中,如果您还有 方法static void f(int x, int y)
,那么对于该方法调用,这将明显优于其他两个方法。
如有疑问,请参阅相关语言规范。对于Java,JLS section 15.12是相关部分。在C# 5 specification中,它是7.5节。
答案 1 :(得分:1)
你有这些函数非常接近彼此或更好的感觉模糊不清让编译器理解,所以编译器会因为看到这些而感到困惑
static void f(int x, double y)
static void f(double x, int y)
为了摆脱编译器的这种混乱或歧义,可以简单地添加以下内容
static void f(int x, int y)
我认为此评论更适合您解释
问题不在于缺少具有两个int参数的方法。 问题是有两种方法同样好 根据Java的匹配方法调用的规则进行匹配 方法。消除现有的f()方法之一,错误将 走开。 - Ted Hopp
答案 2 :(得分:1)
在f(1, 2);
中,这两个数字都可以解释为int
或double
,因此它不明确。你可以这样写:
f(1., 2);
或
f(1d, 2);
但是,使用具有相同参数数量的多个签名重载方法并不是一个好习惯。尽可能避免这种过载是一种很好的做法。
一个典型的例子,说明如何使用相同数量的参数重载问题,来自Joshua Bloch的Effective Java:
public class CollectionClassifier {
public static String classify(Set<?> s) {
return "Set";
}
public static String classify(Collection<?> c) {
return "Unknown Collection";
}
public static void main(String[] args) {
Collection<?>[] collections = {
new HashSet<String>(),
new ArrayList<BigInteger>()
};
for (Collection<?> c : collections) {
System.out.println(classify(c));
}
}
}
这将打印Unknown Collection
两次,很容易被忽视。