Java静态导入

通过实验,我发现即使在静态上下文中,Java非静态方法也会覆盖范围内所有相同的命名方法。 即使不允许参数重载。 喜欢

import java.util.Arrays; import static java.util.Arrays.toString; public class A { public static void bar(Object... args) { Arrays.toString(args); toString(args); //toString() in java.lang.Object cannot be applied to (java.lang.Object[]) } } 

我在规范中找不到任何相关内容。 这是一个错误吗? 如果不是,有没有理由实施这样的语言?

UPD:Java 6不编译此示例。 问题是 – 为什么?

解释很简单,虽然它不会改变行为非常不直观的事实:

在解析要调用的方法时,编译器所做的第一件事就是找到具有正确名称方法的最小封闭范围。 只有这样才会出现重载解析和游戏中的其他内容。

现在发生的事情是包含toString()方法的最小封闭范围是从Ainheritance它的A类。 因此,我们停在那里,不要再搜索。 遗憾的是,接下来编译器会尝试找到给定范围内方法的最佳拟合,并注意到它不能调用任何方法并给出错误。

这意味着永远不会静态导入名称与Object中的方法相同的方法,因为自然在范围内的方法优先于静态导入 (JLS详细描述了方法阴影,但对于这个问题,我认为它更简单记得那个)。

编辑: @alf提交了JLS的正确部分,该部分描述了那些想要全局的人的方法调用 。 它相当复杂,但问题并不简单,所以这是预期的。

它不是一个覆盖。 如果它确实有效, this.toString()仍将访问A的方法而不是Arrays.toString ,如果发生覆盖的话。

语言规范解释了静态导入仅影响static方法和类型的解析:

导入名为n的字段的软件包p的编译单元c中的单静态导入声明d会影响整个c中由c中的静态导入按需声明导入的名为n的任何静态字段的声明。

在包p的编译单元c中的单静态导入声明d,它导入名为n的方法,其中包含签名s,它隐藏了任何名为n的静态方法的声明,其中签名s由c中的static-import-on-demand声明导入,整个c。

在包p的编译单元c中导入名为n的类型的单静态导入声明d会影响以下声明:

  • 由c中的static-import-on-demand声明导入的任何名为n的静态类型
  • 名为n的任何顶级类型 (第7.6节)在p的另一个编译单元(第7.3节)中声明。
  • 由c中的type-import-on-demand声明(第7.5.2节)导入的任何名为n的类型。 整个c。

静态导入不会影响非静态方法或内部类型。

所以toString不会影响非静态方法。 由于名称toString可以引用A的非静态方法,因此它不能引用Arraysstatic方法,因此toString绑定到范围内可用的名为toString的唯一方法,即String toString() 。 该方法不能接受任何参数,因此您会收到编译错误。

第15.12.1节解释了方法解析,必须完全重写,以允许在static方法中隐藏不可用的方法名称,但不允许在member方法内部。

我的猜测是语言设计者希望保持方法解析规则简单,这意味着无论是否出现在static方法中,相同的名称都意味着相同的东西,唯一可以改变的是可用的。

如果您尝试使用类似的代码,那么您将不会遇到任何编译器错误

 import static java.util.Arrays.sort; public class StaticImport { public void bar(int... args) { sort(args); // will call Array.sort } } 

这个编译和你的原因不是因为Object是你的类的父类,所以toString() (或类Object中定义的任何其他方法)仍然限定为Object类。 因此,当编译器从Object类中找到这些方法的匹配签名时,它会给编译器错误。 在我的例子中,因为Object类没有sort(int[])方法,因此编译器正确地将它与静态导入匹配。

我不认为这是一个错误或与正常导入不同的东西。 例如,在正常导入的情况下,如果您有一个与导入的名称相同的私有类,则不会反映导入的私有类。