Java - .class 文件中是否删除了包语句?

Java - Does the package statement is removed in .class file?

我们知道package语句是在javac命令触发时,根据包名创建相关目录。

例如:

// MyClassB.java
package abc.xyz;

class MyClassA{
  // ...
}

class MyClassB{
  // ...
}

现在当我编译这个文件时:

javac -d . MyClassB.java

编译后,我们将有以下包含 .class 个文件的目录结构。

/
 |___ abc
    |___ xyz
        |___ MyClassA.class
        |___ MyClassB.class

现在的问题是,这些MyClassA.classMyClassB.class是否只包含MyClassAMyClassBclass的编译字节码?

下面的语句呢?

package abc.xyz;

在编译过程中是否删除了该语句?或者此语句仅从 MyClassA class 中删除并保留在 MyClassB class 中,因为文件的名称是 MyClassB.java。或者 MyClassB.class 文件在编译后只包含 MyClassB class 字节码,而 package abc.xyz; 在编译过程中也被删除了?如果 package abc.xyz; 在编译时没有被删除,那么当我们在运行时使用这个文件时就会出现问题,因为运行时引擎也会触发 package abc.xyz; 声明字节码版本,所以,这将是一个问题。或者它在编译过程中被删除了?或者字节码只为 classes 而不是为包含 package abc.xyz; 语句的文件创建,这导致 package abc.xyz; 没有成为 .class 文件的一部分。

下图清楚的说明了问题:

谁能解释一下这背后的场景是什么?我谦虚地请求贡献者不要对我的问题打负分,因为我对 java 有一些困惑,所以,我想清除我的 concept.If 仍然我的问题可以打负分,然后它好做,但至少也要回答。

谢谢!!!

它不会任何地方,它被编译为class abc.xyz.MyClassA。您可以看到,如果您使用 javap 反编译 .class

如果您打开任何 class 的 .class 文件,您可以在其中看到包的详细信息。在您的情况下,如果您将在文本编辑器中打开 MyClassA.class,那么您会看到类似 abc/xyz/MyClassA 的内容。 JVM 将像 abc.xyz.MyClassA 一样使用它。这就是如果我们需要在其他 class 中使用此 class 的原因,我们需要像 import abc.xyz.MyClassA.

一样使用它

指令如 package 声明,以及 import 语句,根本不生成任何代码,它们只影响编译器如何处理同一编译单元中的名称。

所以像

这样的声明
package abc.xyz;

public class MyClassA {

}

在包 abc.xyz 中创建具有限定名称 abc.xyz.MyClassA 的 class 或具有简单名称 MyClassA 的 class;两者意思相同

限定名称存储在 .class 文件中,这是与 JVM 唯一相关的信息。

约定SimpleName.class等文件存储在从包名派生的目录中,即abc/xyz/MyClassA.class,遵守[=19] =] 并由标准 class 加载程序使用,以便在请求该名称的 class 时查找文件。显然,有这样的约定让生活更轻松。

原则上,其他存储方法也是可以的,并且有一些已知的。从 Java 9 开始,参考实现有一个模块图像格式,在此之前,有“共享 class 数据存档”,此外还有“Pack200”,一种已弃用的存档格式JDK 11.

删除

请注意,即使是扩展 zip 文件的 jar 文件也不完全是您所看到的。一个 zip 文件由具有限定名称的线性文件条目序列组成,因此在您的情况下,您将有两个条目将它们的名称报告为 abc/xyz/MyClassA.classabc/xyz/MyClassB.class,而工具显示的任何目录结构都是实际上源自这些名称,并不意味着 abcxyz 的嵌套条目实际存在。尽管如此,标准的 class 加载程序也会像该目录结构存在一样使用这些条目,因此将目录结构存储到 zip/jar 文件中的想法没有问题。

但是从Java9开始,同一个class可以有不同的版本,要根据当前的Java版本来选择。用于此的命名方案不是 javac 在存储文件时使用的约定的一部分。