Java虚拟机ClassLoader入门

来源:互联网 发布:单片机编程工资 编辑:程序博客网 时间:2024/06/05 02:00

        最近有强烈的欲望看《深入Java虚拟机》,无奈图书馆一直不开门。偶然间看到网上流传的张龙老师的JVM视频教程,就下载下来准备看看。这一看简直停不下来了,张龙讲得非常好。一口气看完了七讲视频,这里向大家推荐了。这里我把张龙老师的开篇例子和大家分享一下。

        代码片段一:

class Singleton {private static Singleton singleton = new Singleton();public static int counter1;public static int counter2 = 0;private Singleton() {counter1++;counter2++;}public static Singleton getInstance() {return singleton;}}public class MyTest {public static void main(String[] args) {Singleton singleton = Singleton.getInstance();System.out.println("counter1 = " + singleton.counter1);System.out.println("counter2 = " + singleton.counter2);}}
        代码片段二:
class Singleton {public static int counter1;public static int counter2 = 0;private static Singleton singleton = new Singleton();private Singleton() {counter1++;counter2++;}public static Singleton getInstance() {return singleton;}}public class MyTest {public static void main(String[] args) {Singleton singleton = Singleton.getInstance();System.out.println("counter1 = " + singleton.counter1);System.out.println("counter2 = " + singleton.counter2);}}
        这两段代码的执行结果应该是什么呢?大家可以自己运行一下试试,我这里就不卖关子了。代码一的执行结果是counter1 = 1, counter2 = 0,而代码二的执行结果是counter1 = 1, counter2 = 1。为什么会这样呢?我当时也是一头雾水。其实这种奇怪现象的“始作俑者”就是ClassLoader(类加载器)。首先明确一个基本问题,就是Java中的类是需要内存空间的。这是显然的了,类的方法、类的静态变量都是存放在内存中的(当然还有一个对应于该类的Class对象)。Java中的类是如此的多,我们不可能把它们一起加载到内存里。JVM的策略是当代码“直接使用”某个类时,就使用ClassLoader把它加载到内存里。直接使用的情况有如下六种:

                -创建类的实例

                -访问某个类或接口的静态变量,或者是对该静态变量赋值

                -调用类的静态方法

                -反射 (如Class.forName("com.shengsiyuan.Test"))

                -初始化一个类的子类

                -Java虚拟机启动时被表明为启动的类

         除了以上六种情况,其他使用Java类的方式都被看作是对类的被动使用,都不会导致类的初始化。其他几种情况我们先不要管,前面的例子中“直接访问”的情况是调用了Singleton类的静态方法getInstance(),这样的调用导致Singleton类被ClassLoader加载到了内存里。加载之后并没有完事,还有连接和初始化两个步骤。如下图内容所讲:

        验证和解析过程我们就不去研究了,在这个例子中他们没有什么实质性的作用。准备这个过程为类的静态变量分配内存,然后将其初始化为默认值。对于上面的两个例子来说,就是将counter1和counter2都初始化为0,将singleton初始化为null(非基本类型的默认值就是null)。真正出现区别的时间是在初始化过程,这个初始化过程是按变量的声明顺序来的,从上到下依次执行。对于代码片段一,首先new一个Singleton对象,其中调用了构造函数,这行代码执行完毕之后,counter1 = 1, counter2 = 1;紧接着的一行中,没有给counter1指定初始值,所以什么都没干;最后第三行代码中,counter2被赋值为0。所以,代码一最后的结果是counter1 = 1, counter2 = 0。按照同样的方法分析,可以得到代码二的执行结果是counter1 = 1, counter2 = 1。

0 0
原创粉丝点击