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.class
和MyClassB.class
是否只包含MyClassA
和MyClassB
class的编译字节码?
下面的语句呢?
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.class
和 abc/xyz/MyClassB.class
,而工具显示的任何目录结构都是实际上源自这些名称,并不意味着 abc
和 xyz
的嵌套条目实际存在。尽管如此,标准的 class 加载程序也会像该目录结构存在一样使用这些条目,因此将目录结构存储到 zip/jar 文件中的想法没有问题。
但是从Java9开始,同一个class可以有不同的版本,要根据当前的Java版本来选择。用于此的命名方案不是 javac 在存储文件时使用的约定的一部分。
我们知道package
语句是在javac
命令触发时,根据包名创建相关目录。
例如:
// MyClassB.java
package abc.xyz;
class MyClassA{
// ...
}
class MyClassB{
// ...
}
现在当我编译这个文件时:
javac -d . MyClassB.java
编译后,我们将有以下包含 .class
个文件的目录结构。
/
|___ abc
|___ xyz
|___ MyClassA.class
|___ MyClassB.class
现在的问题是,这些MyClassA.class
和MyClassB.class
是否只包含MyClassA
和MyClassB
class的编译字节码?
下面的语句呢?
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.class
和 abc/xyz/MyClassB.class
,而工具显示的任何目录结构都是实际上源自这些名称,并不意味着 abc
和 xyz
的嵌套条目实际存在。尽管如此,标准的 class 加载程序也会像该目录结构存在一样使用这些条目,因此将目录结构存储到 zip/jar 文件中的想法没有问题。
但是从Java9开始,同一个class可以有不同的版本,要根据当前的Java版本来选择。用于此的命名方案不是 javac 在存储文件时使用的约定的一部分。