JVM 如何装载和初始化一个Java class(类)
在Java中,首先编写一个 .java 的源文件;然后,使用Java编译器编译成 .class 的字节码文件。Java在运行时加载 .class 字节码文件。那么,装载 与 初始化 有什么区别呢?一个Java类是什么时候被装载和初始化的?又是如何被装载和初始化的?本文将利用代码示例的方式,详细地阐述这些迷惑问题。
装载一个类
学习过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会首先完成父类的初始化,再执行子类的初始化;对于类中静态的常量,会按照定义的先后顺序完成初始化;最后会保证在初始化之前,每个属性都会有一个默认值。至于类中各种类型成员的初始化顺序细节,建议查看本站的这篇文章。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
My Baits入门(一)mybaits环境搭建
1)在工程下引入mybatis-3.4.1.jar包,再引入数据库(mysql,mssql..)包. 2)在src下新建一个配置文件conf.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 引入外部配置文件 --> <properties resource="jdbc.properties" /> <!-- 配置mybatis运行环境 --> <environments default="development"> <environment id="development"> <!-- type="JDBC" 代表使用JDBC的提交和回滚来管理事务 -...
- 下一篇
2018年人工智能可以在哪些领域最快得到应用和普及?
根据腾讯互娱发布的《2017 Q3 AI 行业全景热度观察》,2017年第三季度,全球AI公司融资总额高达 77.42 亿美元,仅比前两个季度之和低10亿美元,而与2012年同期相比则增长了70余倍。 虽然第四季度还没结束,但10月底旷视科技4.6亿美元的C轮融资额已经刷新了此前由商汤科技所保持的4.1 亿美元的融资记录,也成为全球人工智能企业迄今为止所获得的最大一笔融资。不难看出,火遍整个2017年的人工智能,到了年末依旧是势头不减,甚至很可能再次打破之前的各项融资记录。 回顾过去,从1956年的达特茅斯会议到今天,人工智能已经走过了60多年的历史。在这60多年中,人工智能经历过高峰,也曾跌落到低谷,但从来没有哪一次像今天这样,成为街头巷尾无人不谈的话题。虽然这一定程度上得益于移动互联网时代信息传播效率的飞速提升使得热点话题的影响力得以成千上万倍的扩大。但另一个更重要的原因是,这一次的人工智能复兴与以往的最大区别在于,它让人们真正看到了 AI 技术改变人类未来生活方式的可能性。 用李开复的话说:“今天的人工智能是‘有用’的人工智能……这一次人工智能复兴的最大特点,就是 AI 在多个相...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- CentOS7,CentOS8安装Elasticsearch6.8.6
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS8编译安装MySQL8.0.19
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16