小编给大家分享一下Java虚拟机之类加载的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获、下面让我们一起去了解一下吧!
Java是什么
Java是一门面向对象编程语言,可以编写桌面应用程序,网络应用程序,分布式系统和嵌入式系统应用程序。
一、类加载流程
类加载的流程可以简单分为三步:
- <李>
加载
李> <李>连接
李> <李>初始化
李>而其中的连接又可以细分为三步:
- <李>
验证
李> <李>准备
李> <李>解析
李>下面会分别对各个流程进行介绍。
1.1类加载条件
在了解类接在流程之前,先来看一下触发类加载的条件。
<代码> JVM> 代码不会无条件加载类,只有在一个类或接口在初次使用的时候,必须进行初始化。这里的使用是指主动使用,主动使用包括如下情况:
- <李>
创建一个类的实例的时候,比如使用新<代码> 代码>创建,或者使用反射,克隆,反序列化
李> <李>调用类的静态方法的时候,比如使用<代码> invokestatic> 代码指令
李> <李>使用类或接口的静态字段:比如使用<代码> getstatic <代码>//<代码> putstatic> 代码指令
李> <李>使用<代码>数组> 代码中的反射类方法时
李> <李>初始化子类时,要求先初始化父类
李> <李>含有<代码>主要()代码>方法的类
李>除了以上情况外,其他情况属于被动使用,不会引起类的初始化。
比如下面的例子:
public class Main { ,,,public static void main (String [], args) { ,,,,,,,System.out.println (Child.v); ,,,} } 父{class 静态{,,, ,,,,,,,System.out.println (“Parent init"); ,,,} ,,,public static int v =, 100; } class Child  extends 父母{ ,,,static { ,,,,,,,System.out.println (“Child init"); ,,,} }
输出如下:
父init
引用>
100而加上类加载参数<代码> - xx: + TraceClassLoading> 代码后,可以看到<代码> 代码>孩子确实被加载了:
0.068 [s] [info ,,)(类、负载),com.company.Main [0.069][info ,,)(类、负载),com.company.Parent [0.069][info ,,)(类、负载),com.company.Child Parent 初始化 100年但是并没有进行初始化。另外一个例子是关于<代码> 代码>的,代码如下:
public class Main { ,,,public static void main (String [], args) { ,,,,,,,System.out.println (Test.STR); ,,,} } 测试{class 静态{,,, ,,,,,,,System.out.println (“Test init"); ,,,} ,,,public static final String STR =,“Hello"; }输出如下:
[0.066] [info ,][类、负载]com.company.Main
引用>
你好<代码> 代码>测试类根本没有被加载,因为最终<代码> 代码>被做了优化,编译后的<代码> Main.class 代码>中,并没有引用<代码> 代码>测试类:
0:, getstatic ,,,, 2,,,,,,,,,,,,,,,,,,//, Field java/lang/system . out: Ljava/io/PrintStream; 3:,ldc ,,,,,,,,,, # 4,,,,,,,,,,,,,,,,,,//String ,你好 5:,invokevirtual # 5,,,,,,,,,,,,,,,,,,//, Method java/io/PrintStream.println: (Ljava/lang/String;)V在字节码偏移3的位置,通过<代码> ldc> 代码将常量池第4项入栈,此时在字节码文件中常量池第4项为:
# 3,=, Class ,,,,,,,,,,,,, # 24,,,,,,,,,,,,//;com/company/Test # 4,=,String ,,,,,,,,,,,, 25号,,,,,,,,,,,,//,你好 # 5,=,Methodref ,,,,,,,,, # 26。# 27,,,,,,,,//, java/io/PrintStream.println: (Ljava/lang/String;) V因此并没有对<代码> 代码>测试类进行加载,只是直接引用常量池中的常量,因此输出没有<代码> 代码>测试的加载日志。
1.2加载
类加载的时候,JVM <代码> 代码>必须完成以下操作:
<李>
通过类的全名获取二进制数据流
李> <李>解析类的二进制数据流为方法区内的数据结构
李> <李>Java虚拟机之类加载的示例分析