4

我正在处理 Eclipse 中的一些 Java 代码。代码包含在一个名为 的类Adder中,它在 Eclipse 中位于包中org.processing。类文件中的第一件事是行

package org.processing

Q1) 这条线到底在做什么?为什么会有,它的作用是什么。

代码在 Eclipse 中运行良好,但是,当我进入工作区时,如果我进入 中的src/org/processing/文件夹,当我尝试使用运行时进行src编译,我得到以下错误javac Adder.classjava Adder

java.lang.NoClassDefFoundError: Adder (wrong name: org/processing/Adder)

另一方面,如果我从 src 编译使用

javac org/processing/Adder.java

我可以从src使用中运行它,java org.processing.Adder但仍然不能从处理目录中运行。

Q2) 这是否意味着编译总是相对于目录结构?

最后,如果我 package org.processing从开头删除该行,.class我可以在文件目录中编译和运行该.class文件。

Q3) 为什么会这样?我可以完全理解为代码开发强制执行目录结构,但是一旦您使用字节码,这似乎有点过头了,因为现在我(显然)只能src使用java org.processing.Adder. 现在,我确定我在这里错过了重点,所以如果有人能指出它是什么,那就太好了。

4

4 回答 4

2

编译器在编译时必须能够找到相关的源代码文件。这就是为什么包和目录结构必须与源代码一致。同样,JVM 必须能够找到引用的 .class 文件。所以在运行时需要相同的目录结构。没有比这更复杂的了。

于 2012-09-02T03:47:00.060 回答
2

Q1)这里的问题是,一旦您进入代表您的包层次结构的文件夹,您将其设置为工作目录。它会在 org/processing/Adder 内部查找路径 org/processing/Adder(本质上是从根目录查找 org/processing/Adder/org/processing/Adder)。您需要使用完整路径从根目录调用它。包的目的是 A:将相关的类组织成组。和 B:和 A 一样,Foo.bar 包中的类不能查看其他包中的私有类,因为它们就像该包的内部类,只有它们所在的包才能使用它们

Q2)是的

Q3)路径用作 JVM 了解类文件(每个都包含其字节码)的确切位置的基本结构。如果您更改调用它的位置,您基本上是在尝试更改 JVM 的位置以查找类文件,但它们的真实位置没有改变。

于 2012-09-02T03:47:12.633 回答
1

对于 Q1:包声明允许您保证您的类永远不会被误认为是另一个具有相同名称的类。这就是为什么大多数程序员把他们公司的名字放在包里的原因。不太可能发生冲突。

对于Q2:包结构和目录结构是一一对应的。简而言之,目录和包必须相同,除了包通常位于名为 src 的文件夹下。

对于 Q3:编译后,类文件可能会位于 jar 文件中的相应文件夹中。您的 ant 或 maven 任务将构建 jar 文件,因此除了第一次设置 ant 任务之外,您实际上不必费心处理它。

于 2012-09-02T03:48:39.947 回答
1

简短的回答 -有助于保持您的项目结构井井有条,允许您重用名称(尝试使用两个名为 的类Account),并且是非常大的项目的一般约定。它们只不过是文件夹结构,但为什么要使用它们会严重影响初学者。有趣的是,如果项目少于 5 个类,您可能不需要它。


什么,这条线到底在做什么?为什么会有,它的作用是什么。

线

package org.processing

告诉 Java 这个类文件位于一个名为/org/processing 的文件夹中。 这允许您拥有一个完全定义为org.processing.Processorhere 的类,并且在另一个文件夹中 - 比如说/org/account/processing,您可以拥有一个完全定义为org.account.processing.Processor. 是的,两者都使用相同的名称,但它们不会发生冲突——它们位于不同的包中。如果您决定在同一个类中使用它们,则必须通过使用 import 语句或完全限定的对象名称来明确说明要使用哪一个。

这是否意味着编译总是相对于目录结构?

是的。 Java 和大多数其他语言都有一个称为类路径的概念。这个类路径上的任何东西都可以编译和运行,默认情况下,你所在的当前目录在类路径上,用于编译和执行。要将其他文件放在类路径上,您必须对编译使用另一个命令行调用:

javac -sourcepath /path/to/source MainClass.java

...这会将源路径中的所有内容编译到当前目录,整齐地组织在包语句指定的文件夹结构中。

要运行它们,正如您已经建立的那样,您需要在类路径中包含已编译的源代码,然后通过完全限定的对象名称执行:

java -cp /path/to/source org.main.MainClass

为什么会是这样?

就像我之前说的,这对于非常大的项目,或者涉及很多其他类和需求结构/组织的项目(例如 Android)非常有用。它做了几件事:

  • 它将源代码组织在一个易于定位的结构中。你没有散落在各处的物体。
  • 它使您的对象的范围保持清晰。如果我有一个名为 的包org.music.db,那么很明显我正在处理处理数据库和持久性的对象。如果我有一个名为 的包org.music.gui,那么很明显这个包处理的是演示端。当您想要创建新功能或更新/重构现有功能时,这会有所帮助;你可以记住它的作用,但你记不起它的名字
  • 它允许您拥有具有相同名称的对象。 那里有不止一种类型Map,如果您正在使用将其引入的项目,您希望能够指定 Map获得的类型 - 再次通过导入或完全限定的对象名称完成。
于 2012-09-02T03:56:12.650 回答