【问题标题】:Package name is different than the folder structure but still Java code compiles包名称与文件夹结构不同,但 Java 代码仍可编译
【发布时间】:2012-01-13 19:39:39
【问题描述】:

我正在使用 Notepad++ 编写我的 Java 代码并使用命令提示符来编译和运行它。 以下是我的示例 Java 代码,

    package abraKadabra;

    public class SuperClass{
       protected int anInstance;

       public static void main(String [] abc){
           System.out.println("Hello");
       }
    }

但是,此文件位于以下文件夹结构中:

“usingprotected\superPkg”(usingProtected 是 C 层次结构中某处的文件夹:)

所以,我在这里的包名应该是 usingProtected.superPkg 而不是我写的 abraKadabra。

但是,当我从命令提示符编译这个 Java 代码时,它编译得很好,没有错误或警告。为什么会这样?包名不应该遵循文件夹结构吗? 如果应该,它将如何坚持?

例如如果我的包名是 usingProtected.superPkg,编译器会以相反的顺序检查。当前的工作目录应该是 superPkg,然后父目录应该是 usingProtected 并完成。它是如何检查带有包名的文件夹结构的吗?

【问题讨论】:

    标签: java package directory subdirectory


    【解决方案1】:

    Java 语言规范不强制文件位于某个目录中。它可以选择允许编译器要求公共类位于与类同名的文件中,但我认为包没有类似的东西。 Section 7.2.1 讨论了文件系统中可能的存储选项,但据我所知,它并没有说明强制执行源代码结构。

    然而,在源目录结构中反映包结构是最佳实践 - 并且是一个几乎普遍接受的约定......并且 javac 使用它来尝试查找源文件'没有明确指定要编译。

    请注意,如果您从命令行编译,默认情况下每个类将出现在与相应源文件相同的位置,但如果您使用“-d”选项(例如“-d bin”)编译器会为你构建一个合适的输出目录结构,根植于指定目录。

    【讨论】:

    • 请注意,虽然 JLS 允许这样做,但 Eclipse 不允许:Bug 16209 - Support declared packages that are different from directory location。所以如果你这样做了,不要指望以后再使用 Eclipse...
    • @sleske:确实。请注意,JLS 确实明确允许 编译器表现得像这样,所以当有些人这样做时不应该感到惊讶:)
    • 是这个答案。到今天?
    • @JobHunter69:据我所知,确实如此。你有理由相信它不是吗?
    • 没有。感谢您的帮助
    【解决方案2】:

    经过一番实验,我掌握了如何使用包名并在命令提示符下运行 Java 类文件。

    假设以下是我的 Java 源文件:-

        package mySample;
    
    
        public abstract class Sample{
            public static void main(String... a){
               System.out.println("Hello ambiguity");
            }
        }
    

    此文件位于目录“D:\Code N Code\CommandLine”中。

    现在,当使用以下命令编译源代码时(通过从 cmd 转到上述目录):-

        javac -d . Sample.java
    

    这会自动在我的当前目录中创建“mySample”文件夹。因此,我的类文件 Sample.class 存在于目录“D:\Code N Code\CommandLine\mySample”中。编译器根据我在源代码中提供的包名称创建了这个新文件夹“mySample”。

    因此,如果我将包名指定为“package com.mySample”,编译器将创建两个目录并将我的类文件放在“D:\Code N Code\CommandLine\com\mySample”中。

    现在,我仍在当前工作目录中,即“D:\Code N Code\CommandLine”中。为了运行我的类文件,我给出了以下命令:

        java mySample.Sample
    

    所以,我给出了包的完整层次结构,然后是类名。 Java 解释器将在当前目录中搜索“mySample”目录并在该目录中搜索“Sample.class”。它正确并成功运行它。 :)

    现在,当我问为什么它编译我的错误包源代码时,它会成功编译代码,但是当我运行我的类文件时它会给出 NoClassDefFoundError。所以上面的方法可以用来从命令行使用包名。

    【讨论】:

    • 非常感谢。我花了一整天的时间寻找这个。它帮助我澄清了我的疑虑。
    【解决方案3】:

    如果您正在编译单个类,javac 不需要在别处寻找它。它只会按原样编译文件并将生成的.class 放入同一文件夹中。但是,您通常无法使用该类,除非您将其放入类路径中某个目录中的“abraKadabra”目录中。

    如果你的类使用包中的另一个类,你可能会因为同样的原因在它所在的地方编译它时遇到问题(javac 想要找到这个类并确保它有方法,这样你的类使用)。

    【讨论】:

    • 我一直在试验这个。可以将package 语句更改为与文件夹结构不匹配的内容,但更改import 语句将导致javac 无法编译,因为它找不到import 指定的类
    【解决方案4】:

    Java 编译器在编译源文件时不检查目录结构。正如您所提到的,假设您有一个以指令开头的源文件

    package abraKadabra;
    

    即使文件不包含在子目录 .../abraKadabra 中,您也可以编译该文件。如果源文件不依赖于其他包,它将无错误地编译。但是,生成的程序将不会运行(除非在执行中还包括包名)。当您尝试运行程序时,虚拟机将找不到生成的类。

    【讨论】:

      猜你喜欢
      • 2014-05-04
      • 2016-08-11
      • 2010-12-22
      • 2016-02-29
      • 1970-01-01
      • 1970-01-01
      • 2017-04-20
      • 2013-10-15
      • 1970-01-01
      相关资源
      最近更新 更多