欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java虚拟机装载和初始化一个class类代码解析

程序员文章站 2024-02-29 14:20:52
在 java 应用程序开发中,只有被 java 虚拟机装载的 class 类型才能在程序中使用。只要生成的字节码符合 java 虚拟机的指令集和文件格式,就可以在 jvm...

在 java 应用程序开发中,只有被 java 虚拟机装载的 class 类型才能在程序中使用。只要生成的字节码符合 java 虚拟机的指令集和文件格式,就可以在 jvm 上运行,这为 java 的跨平台性提供条件。下面,我们来看看虚拟机是如何装载和初始化一个 class 类的。

装载一个类

学习过c/c++语言的读者知道,c/c++源代码必须首先别编译成本地的机器代码,然后还需要一个链接代码过程。该链接过程的主要任务就是:合并不同的源码文件产出的中间代码,并最终获得一个可直接执行的应用程序。然后,java语言不是这么做的,java应用中类似于链接过程的步骤是在字节码被装载到jvm中之后再执行的。

正如我们所知,jvm存在不止一个类加载器,不同的加载器使用不同的方式来加载类。但是,它们都只在必须加载类时,才开始装载类。当然,如果已装载完毕的类引用了某些未装载的类,类装载器会进一步去装载这些类,整个的装载过程是递归的。

装载时机与方式

在java中,类的装载策略是由类加载器控制的。我们使用下面这个简单的示例代码来演示类的装载方式与时机:

// testloader.java
package compiler;
public class testloader {
public static void main(string[] args) {
system.out.println("test");
}
}
// a.java
package 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 修改成如下所示:

package compiler;
public class testloader {
public static void main(string[] args) {
system.out.println("test");
a a = new a();
a.method();
}
}

再次执行同样的运行命令,我们获得输出结果变成如下所示:

[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类的全部内容,希望对您有所帮助。

感谢大家对本站的支持!