Java静态导入

时间:2012-01-23 13:11:59

标签: 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);     //toString() in java.lang.Object cannot be applied to (java.lang.Object[])
    }
}

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

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

4 个答案:

答案 0 :(得分:24)

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

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

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

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

编辑:@alf为那些想要全貌的人提交了describes the method invocation的JLS的正确部分。它相当复杂,但问题并不简单,所以这是预期的。

答案 1 :(得分:4)

这不是一个覆盖。如果确实有效,this.toString()仍会访问A而不是Arrays.toString的方法,如果覆盖发生的情况就是这样。

language specification解释静态导入仅影响static方法和类型的解析:

  

在包p的编译单元c中导入名为n的字段的单静态导入声明d会影响由c中的静态导入按需声明导入的名为n的任何静态字段的声明,贯穿c

     

在包p的编译单元c中的单静态导入声明d,它导入一个名为n的方法,其中包含签名s,其中包含名为n的任何静态方法的声明,其中包含由签名导入的签名s c中贯穿c的静态导入按需声明。

     

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

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

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

因此toString不会影响非静态方法。由于名称toString可以引用A的非静态方法,因此它不能引用static的{​​{1}}方法,因此Arrays绑定到唯一可在范围内使用的名为toString的方法,即toString。该方法不能接受任何参数,因此您会收到编译错误。

Section 15.12.1解释了方法解决方案,必须完全重写,以允许在String toString()方法中隐藏不可用的方法名称,但不允许隐藏在static方法内。

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

答案 2 :(得分:1)

如果您尝试关注类似的代码,那么将不会获得任何编译器错误

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[])方法,因此编译器正确地将它与静态导入匹配。

答案 3 :(得分:0)

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