为什么可以导入与嵌套类同名的类?

3
请看下面的代码:

考虑以下代码:

import java.util.Calendar;

class Demo
{
    class Calendar {}

    public static void main (String[] args) {
      // System.out.println(Calendar.DAY_OF_WEEK);  // Would be an error.
    }
}

这段代码编译没有问题;但如果你在Demo中引用Calendar时,你将会引用到Demo.Calendar,而不是java.util.Calendar

这个import显然是多余的。但很奇怪它被允许存在,因为根据JLS Sec 7.5.1的规定,你不允许导入与同一编译单元中定义的顶级类名相同的类:

import java.util.Calendar;  // error: Calendar is already defined in this compilation unit

class Calendar {}

第一个代码示例中这样的导入不会在编译时出错,是否有实际原因?


你误读了JLS。它并不禁止导入与顶级类相同的名称,而是禁止导入名称“n”,如果“编译单元还声明了一个简单名称为n的顶级[sic]类型”。这不是你展示的情况。 - Lew Bloch
@LewBloch,我不明白你所指出的区别。能否请您提供一个示例来说明这种差异? - Andy Turner
我所说的“不允许导入与顶级类同名的类”的情况是第二种情况,即我正在导入Calendar并且有一个名为Calendar的顶级类。我知道为什么第二种情况是被禁止的,但我很惊讶规范没有规定第一种情况也应该被禁止。 - Andy Turner
@LewBloch 但无论我意思是什么,请你能否提供一个例子来说明你的评论“它不禁止导入与顶级类相同的名称,而是禁止导入名称n,如果‘编译单元还声明了一个简单名称为n的顶级[sic]类型’。”。我看不出你试图做出的区别。 - Andy Turner
1
“我很惊讶规范没有规定第一个情况也应该被禁止。” 我无法评论你的惊讶,@AndyTurner;这是一种心理反应。唯一的冲突是导入的简单名称与编译单元中顶级类的名称匹配。区别在于它仅禁止在具有冲突命名的顶级类的定义中出现。类完全可以导入与编译单元中某个“其他”顶级类相同的名称。因此,Demo 可以很好地导入 Calendar - Lew Bloch
显示剩余2条评论
2个回答

3
我能想到的唯一情况是,当您有一个嵌套两次(或更多)的类与导入相同的名称时:
import java.util.Calendar;

class Demo {
  static class Nested {
    static class Calendar {}

    static void useNested() {
      System.out.println(Calendar.class);  // Demo.Nested.Calendar
    }
  }

  static void useImported() {
    System.out.println(Calendar.class);  // java.util.Calendar
  }

  public static void main(String[] args) {
    Nested.useNested();
    useImported();
  }
}

Ideone演示

在这种情况下,嵌套的Calendar类不会自动显示在Nested类的作用域之外,因此在外部使用导入的Calendar类,例如在useImported方法中。

我并不真正认为这是一个“实际”的用途,因为在每个上下文中使用哪个很容易混淆,绝对值得避免。但是,我仍然对这种情况感到有趣。


我想还有另一个类似的情况:

import java.util.Calendar;

class Demo {
  static void useImported() { ... }
}

class Demo2 {
  class Calendar {}

  static void useNested() { ... }
}

(这些类在同一编译单元中)。基本上与上述想法相同。

0

我认为,如果你导入一个类,它会在编译单元的全局空间中可见。但是,如果你将编译单元或顶级类命名为与导入相同的名称,则基本上会与导入发生冲突,因此JVM无法知道哪个是哪个。由于它正在编译一个类,所以会出现导入错误。

此外,当它在另一个类中时,你会在那里遮蔽导入。这与全局/类级变量和方法级变量以相同名称定义时隐藏它们的方式类似。

希望这可以帮助到你。


因此,对于JVM来说,它将是模棱两可的。实际上并不是模棱两可,你只是不能引用导入的类,因此被阻止了。这就像防止诸如 "" instanceof Integer 这样的事情一样:对于JVM来说并不是模棱两可的,只是可能表示程序员的错误。 - Andy Turner
@AndyTurner - 我在解释,如果JVM允许在同一编译单元中使用相同的导入和顶级类名称。抱歉,也许我表达不太清楚。 - Avinash Anand
是的,我理解了,并且我想说这并不含糊:它是冗余的,就像"" instanceof Integer是写false的多余方式一样,因此被编译器禁止。 - Andy Turner

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