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

时间:2019-01-18 11:18:43

标签: 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.classMyClassB.class仅包含MyClassAMyClassB类的编译字节码吗?

以下内容如何?

package abc.xyz;

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

下面的图片清楚地说明了问题: enter image description here

任何人都可以解释这背后的情况吗?这是我对贡献者的谦虚要求,不要对我的问题打负号,因为我对Java有一些困惑,因此,我想清除我的概念。如果我的问题仍然可以打负号,那可以,但是至少可以回答也是

谢谢!!!

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

诸如package声明和import语句之类的指令根本不会生成任何代码,它们只会影响编译器对待同一编译单元中名称的方式。

像这样的声明

package abc.xyz;

public class MyClassA {

}

在包abc.xyz.MyClassA中创建一个限定名称为MyClassA的类或简单名称为abc.xyz的类;两者都一样。

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

有一个惯例SimpleName.class之类的文件存储在从包名(即abc/xyz/MyClassA.class,由javac遵守并由标准类加载器在请求具有该名称的类时查找文件。显然,有了这样的约定会使生活更轻松。

原则上,其他存储方法也是可能的,并且有一些已知的存储方法。从Java 9开始,参考实现具有模块映像格式,在此之前,存在“共享类数据存档”,此外,还有“ Pack200”,一种已被JDK 11删除的存档格式。 >

请注意,即使jar文件(扩展的zip文件)也不完全是您所看到的。一个zip文件由具有限定名称的线性文件条目序列组成,因此,在您的情况下,您将有两个条目将其名称分别报告为abc/xyz/MyClassA.classabc/xyz/MyClassB.class,而工具显示的任何目录结构都是实际上从这些名称派生而来,并不意味着abcxyz的嵌套条目实际上存在。仍然,标准类加载器也将以与存在此目录结构相同的方式来使用这些条目,因此将目录结构存储到zip / jar文件中的想法没有问题。

但是从Java 9开始,同一类可以有不同的版本,具体取决于当前的Java版本。用于此的命名方案不是存储文件时javac所使用的约定的一部分。

答案 2 :(得分:0)

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