为什么同名静态方法的静态导入是合法的?

31

假设我们有以下这些包和类:

package p1;

public class A1 {
    public static void a() {}
}

package p2;

public class A1 {
    public static void a() {}
}

package p3;

import static p1.A1.a;
import static p2.A1.a;

public class A1 {
    public static void test() {

    }
}

我在想为什么静态方法的导入在包 p3 中是合法的(不会导致编译时错误)?我们无法在 test() 方法中进一步使用它们,因为这样的用法会导致编译时错误。

为什么普通类的导入不是同样的情况。 假设我们想将类 A1 从包 p1p2 导入到 p3 中:

package p3;
import p1.A1;
import p2.A1;

这种导入方式是非法的,会在编译时引发错误。


因为程序包和类的组合可以唯一地区分一个方法与另一个方法。 - duffymo
@duffymo - 他特别想知道为什么静态导入方法时没有名称冲突,而您并未解决这个问题。 - Dave Richardson
我想我可以。我没有问题区分a.b.c和a.d.c;编译器也没有。 - duffymo
3个回答

45
静态方法的不确定性可以在调用该方法时解决。
例如,如果您有两个静态方法的导入,看起来像这样:
void frobnicate(int i);
// and
void frobnicate(boolean b);

然后你可以导入并使用两者,因为编译器可以根据传递的参数判断使用哪个(frobnicate(1) 调用第一个,frobnicate(true) 调用第二个)。
对于类来说,这是不可能的:Foobar a; 单独不能告诉你想要哪个 Foobar 类。
还要注意,单个静态导入可以导入多个名称。根据 JLS 的相关部分(我强调):
引用如下:

单个静态导入声明从类型中导入给定简单名称的所有可访问静态成员。

例如,如果上述两个 frobnicate 方法位于同一类中,则单个 static 导入可以导入它们两个。

有趣的事实:Groovy 也允许这样做,但是如果你像我一样不够小心,在运行时它会抛出 groovy.lang.MissingMethodException: No signature of method 异常。错误消息中还会列出 可能的解决方案,其中包含隐藏了你首先尝试调用的方法名称。我花了一个小时才弄清楚这个问题。 - Kohányi Róbert
问题在于为什么编译器允许这样做,即使它“知道”具有相同名称的两个静态方法具有相同的签名。 - Dávid Horváth
如果您可以重现这种歧义,那么我建议提交一个bug。这绝对是编译器应该避免的事情。 - Gili

2
这是因为你给所有这些类都取了同样的名字。每次调用静态方法时,它都会在最近的类中查找,而在此情况下,它是在 p3 中的 A1 类中查找,而该类并不包含静态方法 a()。请始终记住,类名应该是唯一的,永远不要与其他类重名。

0

我猜测,虽然没有语言规范的支持,但方法可以进行重载,但字段/类型不能;因此Java允许从不同类中导入相同名称的方法。

但是,相同签名的两个方法不能存在于同一类中;它们也不应该被导入。

即使这两个方法具有不同的签名,这仍然是一个坏主意。名称的含义非常重要,它应该很清晰。我们可以处理来自1个类的重载方法,但跨类的“重载”则有些牵强。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接