时间:2021-05-20
在 java 应用程序开发中,只有被 java 虚拟机装载的 Class 类型才能在程序中使用。只要生成的字节码符合 java 虚拟机的指令集和文件格式,就可以在 JVM 上运行,这为 java 的跨平台性提供条件。下面,我们来看看虚拟机是如何装载和初始化一个 class 类的。
装载一个类
学习过C/C++语言的读者知道,C/C++源代码必须首先别编译成本地的机器代码,然后还需要一个链接代码过程。该链接过程的主要任务就是:合并不同的源码文件产出的中间代码,并最终获得一个可直接执行的应用程序。然后,Java语言不是这么做的,Java应用中类似于链接过程的步骤是在字节码被装载到JVM中之后再执行的。
正如我们所知,JVM存在不止一个类加载器,不同的加载器使用不同的方式来加载类。但是,它们都只在必须加载类时,才开始装载类。当然,如果已装载完毕的类引用了某些未装载的类,类装载器会进一步去装载这些类,整个的装载过程是递归的。
装载时机与方式
在Java中,类的装载策略是由类加载器控制的。我们使用下面这个简单的示例代码来演示类的装载方式与时机:
// TestLoader.javapackage compiler;public class TestLoader {public static void main(String[] args) {System.out.println("test");}}// A.javapackage compiler;public class A {public void method(){System.out.println("inside of A");}}再看一下它们的目录结构:
|-src|--compiler|------A.java|------TestLoader.java为了获得每个类加载的信息,我们可以使用如下的命令来运行程序。其中的 “-verbose:class” 参数告诉 JVM 打印出每次加载类的信息。
java -verbose:class -classpath /home/ron/workspace/UltimateTest/bin/ compiler.TestLoader整个程序的输出信息很繁琐,我们摘取其中重要的部分展示如下:
[Loaded sun.misc.JavaSecurityProtectionDomainAccess from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar][Loaded java.security.ProtectionDomain$2 from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar][Loaded java.security.ProtectionDomain$Key from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar][Loaded java.security.Principal from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar][Loaded compiler.TestLoader from file:/home/xiwang/workspace/UltimateTest/bin/]test[Loaded java.lang.Shutdown from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar][Loaded java.lang.Shutdown$Lock from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar]现在,假设我们把TestLoader.java修改成如下所示:
再次执行同样的运行命令,我们获得输出结果变成如下所示:
[Loaded sun.misc.JavaSecurityProtectionDomainAccess from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar][Loaded java.security.ProtectionDomain$2 from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar][Loaded java.security.ProtectionDomain$Key from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar][Loaded java.security.Principal from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar][Loaded compiler.TestLoader from file:/home/xiwang/workspace/UltimateTest/bin/]test[Loaded compiler.A from file:/home/xiwang/workspace/UltimateTest/bin/]inside of A[Loaded java.lang.Shutdown from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar][Loaded java.lang.Shutdown$Lock from /usr/local/java/jdk1.6.0_34/jre/lib/rt.jar]读者可仔细查看两者的区别,可以发现只有当 类A 被使用时,该类对应的 A.class 才会被装载。总结起来,一个类的加载条件是:
(1)当使用 new 操作符执行某类时。比如 SomeClass some = new SomeClass()。
(2)当已加载类中有一个静态引用指向某类时。 比如 System.out 。
初始化时机与方式
在Java中,一个类被加载完毕后,不会立即执行类的初始化工作。当类中的符号被第一次使用时,该类才开始被初始化。在初始化顺序方面:JVM会首先完成父类的初始化,再执行子类的初始化;对于类中静态的常量,会按照定义的先后顺序完成初始化;最后会保证在初始化之前,每个属性都会有一个默认值。至于类中各种类型成员的初始化顺序细节,建议查看本站的这篇文章。
总结
以上就是本文关于虚拟机如何装载和初始化一个Java class类的全部内容,希望对您有所帮助。
感谢大家对本站的支持!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
一、类的加载机制 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机
类的初始化 在初始化阶段,Java虚拟机执行类的初始化语句,为类的静态变量赋予初始值。 在程序中,静态变量的初始化有两种途径: 1.在静态变量的声明处进行
Java中初始化块详解在Java中,有两种初始化块:静态初始化块和非静态初始化块.静态初始化块:使用static定义,当类装载到系统时执行一次.若在静态初始化块
class的装载在讲class的初始化之前,我们来讲解下class的装载顺序。以下摘自《ThinkinginJava4》由于Java中的一切东西都是对象,所以许
Class.forName(xxx.xx.xx)返回的是一个类一.首先你要明白在java里面任何class都要装载在虚拟机上才能运行。1.forName这句话就