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

时间:2015-05-22 13:57:08

标签: java compilation package

我认为我无法理解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包。

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

4 个答案:

答案 0 :(得分:16)

正如您(隐式)承认的那样,如果是默认包,则不是必需来声明包的名称。让我们把这个狡辩放在一边......

这种看似冗余的原因是没有package声明,Java 1 源代码的含义将是模糊的。例如,路径名为" /home/steve/project/src/com/example/Main.java"的源文件;可能有7个不同的完全限定名称,具体取决于您编译代码的方式。最有可能的是,只有其中一个将是"正确的"一。但是你不能通过查看(仅)一个源文件来判断哪个FQN是正确的。

还应该注意,Java语言规范不要求根据包来组织源代码树。这是一个(大)Java编译器系列的要求,但是可以编写一个不需要这个的符合编译器。例如:

  • 源代码可以保存在数据库中。
  • 源代码可以保存在具有随机文件名的文件树中。

在这种情况下,package声明不会与文件路径名或(必要)任何内容重复。但是,除非有一些冗余,否则找到正确的来源" file"对于一个类来说,编译器会很昂贵......对于程序员来说也是有问题的。

上述考虑因素是大多数Java工具链依赖文件树结构来定位源和编译类的实际原因。

1 - 我的意思是Java的假设方言,它不需要package声明。

答案 1 :(得分:7)

转过头来问题:

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

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

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

这有帮助吗?

答案 2 :(得分:3)

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

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

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

答案 3 :(得分:1)

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

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

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

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

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