为什么java源文件需要包声明?

我想我无法理解java包结构,对我来说,java文件中有一个包声明似乎是多余的,然后还需要出现在与包名匹配的目录中。 例如,如果我有一个MyClass.java文件:

 package com.example; public class MyClass { public static void main(String[] args) { System.out.println("Hello, World"); } } 

然后我将需要将此文件放在com/example ,相对于基本目录,我将从基本目录执行java com.example.MyClass来运行它。

为什么编译器不能通过查看目录结构来推断包名? 例如,如果我从基本目录javac com\example\MyClass.java编译文件,我不明白为什么MyClass.java不会隐含属于com.example包。

我知道有一个默认包,但似乎源文件中的包声明仍然是冗余信息?

正如您(隐式)承认的那样,在默认包的情况下,您不需要声明包的名称。

忽略那个狡辩…这种看似冗余的原因是,如果不需要package声明,Java源代码的含义就会模糊不清。 例如,路径名为“/home/steve/project/src/com/example/Main.java”的源文件可能有7个不同的完全限定名称…取决于您编译代码的方式。 最有可能的是,其中只有一个是“正确的”。 但是,通过查看(仅)源代码文件,您将无法分辨哪一个是正确的。

还应注意,Java语言规范不要求您根据包来组织源代码树。 这是一个(大)Java编译器系列的要求,但是可以编写一个不需要这个的符合编译器。 在这种情况下, package声明不会重复。

转过头来问题:

假设package语句是重要的 – 它表示类的名称空间并且属于类文件。

所以现在问题是 – 为什么类必须在与其包匹配的文件夹中?

答案是,它使得查找它们变得更加容易 – 它只是组织它们的好方法。

这有帮助吗?

您必须记住,包不只是指示文件夹结构。 文件夹结构是用于匹配包名称的常规Java,就像类名必须与文件名匹配的约定一样。

需要一个包来消除类与其他具有相同名称的类的歧义。 例如, java.util.Datejava.sql.Date不同。 该包还允许访问package-private方法或成员到同一包中的其他类。

你必须反过来看它。 该类包含有关其自身,类名和包名的所有信息。 然后,当程序需要它,并且尚未加载类时,JVM通过查看与包名称匹配的文件夹结构以及与其类名匹配的文件名的类来知道在哪里查找它。

事实上,根本没有这样的义务。

Oracle JDKs javac (我相信大多数其他实现)也很乐意编译你的HelloWorld类,无论它在哪个目录以及你在源文件中声明了什么包。

目录结构进入图片的位置是编译多个相互引用的源文件 。 此时编译器必须能够以某种方式查找它们。 但它在源代码中的所有内容都是引用类的完全限定名称(甚至可能尚未编译)。

在运行时,故事类似:当需要加载类时,其完全限定名称是起点。 现在,类加载器的工作是基于单独的FQN找到.class文件(或ZIP文件中的条目,或任何其他可想象的源),并且分层文件系统中最简单的事情是将包名称转换为目录结构。

唯一的区别是,在运行时,您的“独立”类也必须由VM加载,因此需要查找它,因此它应该在正确的文件夹结构中(因为这是引导类加载器的工作方式)。