为何Java的有包名的类不能引用默认包中的类

有两个java类,源代码如下:

 //没指定包名,也就是在默认包中public class B {
  public void print(){
    System.out.println("Printed By B Class");
  }
}
 package com.unmi;
import B; //引用默认包中的B类
public class A {
  public static void main(String[] args) {
    B b = new B(); //在A中想要引用默认包中的B类
  }
}

先不说在IDE中如何编译它们以及会提示什么语法错误,只是用命令javac来编译它们,先是把它们放在同一个目录下,注意的是,虽然A.java有package unmi.com;声明,我们还是先把它放在下B.java同一目录,希望由javac命令来生成相对应的包目录。

执行1.4或5.0或者是6.0的jdk所带的javac命令编译,提示的错误都是一样的

C:\Documents and Settings\unmi\jbproject\test\src>C:\Java\j2sdk1.4.2_10\bin\javac -d .\ A.java
或 C:\Documents and Settings\unmi\jbproject\test\src>C:\Java\jdk1.5.0_06\bin\javac -d .\ A.java
或 C:\Documents and Settings\unmi\jbproject\test\src>C:\Java\jdk1.6.0\bin\javac -d .\ A.java

错误为:

A.java:3: 需要 '.'
import B; //引用默认包中的B类
        ^
1 错误

如果把 A.java的 import B; 这一行注释掉,用上面的三种jdk进行编译也是出现同样的错误

A.java:7: 找不到符号
符号: 类 B
位置: 类 unmi.com.A
    B b = new B();
    ^
A.java:7: 找不到符号
符号: 类 B
位置: 类 unmi.com.A
    B b = new B();
              ^
2 错误

总之是在带有包名的 A类中不知道怎么去引用默认包(没有包声明)中的类B。事情到此为止也就只会提出一个疑问:Java为何不让带包名的类访问不带包名的类呢?到底有何用意,为什么要有这种限制呢?

可是奇怪的事情还在发生,如果我用1.2或1.3的jdk中的javac编译器来编译上面那两个代码,却是可以编译通过的,

C:\Documents and Settings\unmi\jbproject\test\src>D:\Borland\JBuilder7\jdk1.3.1\bin\javac -d .\ A.java

执行后一切正常,编译出了B.class文件在正前目录下,并且在建立的com\unmi目录中生成了A.class文件,用1.2的jdk的javac编译我在SunOS 5.8操作系统下试过,也没问题的。只要能够成功编译,无论在哪种版本的JVM中执行A.class都能得到预期结果,在A.class中调用B的实例方法print()打印出 Printed By B Class。

于是可以看出,这种所谓带包名的类不能访问不带包名的类只是不同版本的java编译器玩的把戏而已。

回到编译器中来说,用JBuilder7能正常编译以上代码,无论工程选择何种版本的jdk(比1.3高);而用JBuilder2005或是Eclipse3.2(其他版本的Eclipse还没有试验过)则不能编译以上代码,会提示以上的语法错误,不管工程选择的是1.2或1.3的jdk也无济于事。当然把以上两代码放在工程中的话需要把A.java放到com\unmi目录中的。看来IDE也有他们自己的独特的行为,大约为启动IDE本身的JVM的版本所决定(我的猜测)。

写下这个东西只要阐明一种现象(这也是我偶然用JBuilder2006打开一个JBuilder7中正常使用的工程出现错误才意识到的,而且不能轻易苟同某些人的坚持说非要用JBuilder7才行,同时他们还忽略了一个问题,生成的类既然需要拿到SunOS 5.8下的jvm1.2中运行,那何不一改JBuilder中该工程的Target JVM属性值为All Java SKDs即可)�M角笠桓鼍烤梗比辉谄绞北嗦胫写罂刹槐�(并且是不应该)试图让包中的类去引用默认包中的类,为使每个类都体现出层次上的关系,应置于某一命名包中,除非一种例外,那是一个统领其他类的类,比如说Main,启动主程序的类,可以放在默认包中(不声明包名),因为它也不会被其他包中的类引用。

继续重复留下那样一个问题:新的JDK的编译器为何要试图阻止从有包名的一个java类引用默认包(未声明包名)的类呢?

参考:1. Java 2 Platform, Standard Edition Version 1.4.0 Compatibility with Previous Releases   
    
The compiler now rejects import statements that import a type from the unnamed namespace. Previous versions of the compiler would accept such import declarations, even though they were arguably not allowed by the language (because the type name appearing in the import clause is not in scope). The specification is being clarified to state clearly that you cannot have a simple name in an import statement, nor can you import from the unnamed namespace.

To summarize, the syntax

is no longer legal. Nor is the syntax

which would import a nested class from the unnamed namespace. To fix such problems in your code, move all of the classes from the unnamed namespace into a named namespace.

        2. Java Language Specification Third Edition(7.4.2 Unnamed Packages)

A compilation unit that has no package declaration is part of an unnamed package.


Note that an unnamed package cannot have subpackages, since the syntax of a package declaration always includes a reference to a named top level package.


As an example, the compilation unit:


defines a very simple compilation unit as part of an unnamed package.


An implementation of the Java platform must support at least one unnamed package; it may support more than one unnamed package but is not required to do so. Which compilation units are in each unnamed package is determined by the host system.


In implementations of the Java platform that use a hierarchical file system for storing packages, one typical strategy is to associate an unnamed package with each directory; only one unnamed package is observable at a time, namely the one that is associated with the "current working directory." The precise meaning of "current working directory" depends on the host system.


Unnamed packages are provided by the Java platform principally for convenience when developing small or temporary applications or when just beginning development.

本文链接 https://yanbin.blog/java-cannot-import-default-package/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

5 Comments
Inline Feedbacks
View all comments
zhruo@163.com
zhruo@163.com
16 years ago

这个问题我也发现了,我用的IDE工具是ECLIPSE,可见这不是IDE的毛病,而是与java本身有关。

希望得到高手指点。

隔叶黄莺
16 years ago

把这认为 Java 一个强制约定的规范就行了,或许 1.3 下允许这么做是被忽略了,因为正式项目中肯定是要把类放在包中的,所以在实际中这不应该成为问题的。

duduli
16 years ago

这是eclipse遗留问题,或是以前设计问题。同一个项目想产生“不同的项目”。

隔叶黄莺
16 years ago

这完全不关 Eclipse 的事,因为你一直用的 Eclipse,Eclipse 似乎难逃其责。你可以脱离 Eclipse 来重现这个问题。这是 Java 编译器制定的规则,而这样的规则应该说有其很积极的意义。

leven
leven
15 years ago

高手果然是高手呀,嘿嘿:)