我们知道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
类的编译字节码吗?
以下内容如何?
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
文件的一部分。
任何人都可以解释这背后的情况吗?这是我对贡献者的谦虚要求,不要对我的问题打负号,因为我对Java有一些困惑,因此,我想清除我的概念。如果我的问题仍然可以打负号,那可以,但是至少可以回答也是
谢谢!!!
答案 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.class
和abc/xyz/MyClassB.class
,而工具显示的任何目录结构都是实际上从这些名称派生而来,并不意味着abc
和xyz
的嵌套条目实际上存在。仍然,标准类加载器也将以与存在此目录结构相同的方式来使用这些条目,因此将目录结构存储到zip / jar文件中的想法没有问题。
但是从Java 9开始,同一类可以有不同的版本,具体取决于当前的Java版本。用于此的命名方案不是存储文件时javac所使用的约定的一部分。
答案 2 :(得分:0)
如果打开任何一个类的.class文件,您将看到其中的软件包详细信息。如果您要在文本编辑器中打开MyClassA.class
,则可以看到类似abc/xyz/MyClassA
的内容。 JVM将像abc.xyz.MyClassA
一样使用它。这就是如果我们需要在其他一些类中使用该类的原因,则需要像import abc.xyz.MyClassA
这样使用它。