Java静态导入

Java静态导入,java,scope,language-design,overloading,static-import,Java,Scope,Language Design,Overloading,Static Import,通过实验,我发现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);

通过实验,我发现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[])
    }
}
我在规范中找不到关于这个的任何东西。这是一个bug吗?如果不是,有什么理由实现这样的语言吗


UPD:java6不编译此示例。问题是——为什么?

它不是覆盖。如果它确实起作用,
this.toString()
仍将访问
A
的方法,而不是
Arrays.toString
,就像发生重写时一样

说明静态导入仅影响
静态
方法和类型的分辨率:

在包p的编译单元c中,导入名为n的字段的单个静态导入声明d会在整个c中隐藏由c中的静态按需导入声明导入的名为n的任何静态字段的声明

包p的编译单元c中的单个静态导入声明d导入了名为n且签名为s的方法,它在整个c中隐藏了名为n且签名为s的任何静态方法的声明

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

  • 由c中的按需静态导入声明导入的名为n的任何静态类型
  • 在p的另一个编译单元(§7.3)中声明的名为n的任何顶级类型(§7.6)
  • 由c中的类型按需导入声明(§7.5.2)导入的名为n的任何类型。 贯穿c
静态导入不会影响非静态方法或内部类型

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

解释方法解析,必须完全重写,以允许在
静态
方法中隐藏不可用的方法名称,而不是在
成员
方法中隐藏不可用的方法名称


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

解释很简单,尽管它没有改变行为高度不直观的事实:

在解析要调用的方法时,编译器要做的第一件事是找到具有正确名称的方法的最小封闭范围。只有这样,其他的事情,如超载决议和合作的游戏

现在这里发生的是,包含
toString()
方法的最小封闭范围是从
对象继承它的类a。因此,我们停在那里,不再进一步搜索。不幸的是,接下来编译器试图在给定的范围内找到最适合的方法,并注意到它不能调用其中任何一个,并给出了一个错误

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


编辑:请提交JLS的正确部分,供那些想要完整图片的人使用。这相当复杂,但问题也不简单,所以这是意料之中的。

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

如果您尝试遵循类似的代码,则将不会得到任何编译器错误

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

之所以编译而您不编译,是因为
toString()
(或类对象中定义的任何其他方法)的作用域仍然是对象类,因为对象是类的父对象。所以,当编译器从对象类中找到这些方法的匹配签名时,它会给出编译器错误。在我的示例中,由于对象类没有
sort(int[])
方法,因此编译器正确地将其与静态导入匹配。

它似乎引用了它的超级对象的
toString()
IMHO,所以整个静态导入功能是一个糟糕的概念,污染了名称空间并扰乱了代码的可读性。不要偷懒,键入静态函数的封闭类/接口并不难,我们有IDE。尽量避免使用静态导入。@Jigar Joshi,这很正常。但是我找不到任何关于他的东西。而且,我们不能从静态上下文调用
Object.toString
,所以我看不到这种行为有任何逻辑。@bucmeh。静态导入在许多情况下都非常好,可以极大地提高可读性。我无法想象没有它们使用模拟库;那将是一种暴行。@Dave我同意,你只需要理解陷阱——因为这些陷阱可能是不好的。在这种情况下,这并不是那么糟糕,因为我们只是得到了一个编译错误,但在最坏的情况下,我们可能调用了错误的函数,这当然会带来有趣的调试。除了方法
bar
是静态的外,没有实例可以调用
toString()
upon@StasKurilin解释得更清楚。它表示实例方法
Object.toString()
的声明隐藏了任何其他方法