类的加载、连接、初始化
一、先来讲讲java虚拟机和程序的生命周期:
在如下几种情况Java虚拟机会结束生命周期:
—执行System.exita() 方法
—程序正常之行结束
—程序在执行过程中遇到了异常或者错误而 异常终止
—操作系统出现错误而导致java虚拟机进程终止
二、类的加载、链接与初始化
1、加载:查找并且加载类的二进制数据到内存中
2、连接:
—验证:确保被加载的类的正确性
—准备:为类的静态变量分配内存,将其初始化为默认值。比如说,有一个类Person,代码如下:
<pre name="code" class="java">class Person{
//静态变量
public static int value1=9;
public static int value2=0;
public static int value3;
//一系列的方法
public void method(){};
准备阶段就是为静态变量value1、value2、value3、分配内存,并且将它们设为默认值:0 。
—解释:将类中的符号引用转变为直接引用。在这里解释下符号引用和直接引用。比如说有如下的People类和car类:
Car:
<pre name="code" class="java">public class Car{ //有一个方法run public void run(){ System.out.println("car run"); }
People:
<pre name="code" class="java">public class People{ Car car; public void travel(){ this.car.run(); } }
其中可以将代码块 this.car.run() 理解为为符号引用,在解析的过程中java虚拟机会将该符号引用转化为一个指向了Car 类的 run() 方法的指针。
3、初始化:为类的静态变量赋予正确的初始值。就那刚才的person类来说,进行初始化的过程中才会将value1的值设置为9,value2的值设置为0,而value3的将保持为默认值:0.
好了,再举一个例子来说明类的家安在,链接与初始化的过程。假设有两个类,Singleton和一个含有主类的Test类。
Singleton:阅读代码的时候请注意一行被注释的代码
<pre name="code" class="java">public class Singleton {
public static Singleton singleton=new Singleton();
public static int value1=1;
public static int value2=0;
//public static Singleton singleton=new Singleton();
private Singleton(){
value1++;
value2++;
}
public static Singleton getSingleton(){
return singleton;
}
主类:
<pre name="code" class="java">public class Test {
public static void main(String[] args){
Singleton s=Singleton.getSingleton();
System.out.println("value1= "+s.value1);
System.out.println("value2= "+s.value2);
}
}
这时候的输出结果为:
value1 = 1
value2 = 0
在这里解释下程序的执行过程就知道该输出结果的由来。
根据之前的讲解,主方法调用了Sington这个类,于是java虚拟机会将Singleton.class文件加载到内存中,接着是执行验证操作。
接着是执行准备操作,由于静态代码块的顺序为:public static Singleton singleton=new Singleton();
public static int value1=1;
public static int value2=0;
程序底层的执行顺序为:1、为静态变量分配内存和初始值,即: public static Singleton singleton=null;
public static int value1=0;
public static int value2=0;
2、执行静态代码块:
singleton=new Singleton(); ——>这一步会将value1的值变为1,value的值变为1 (执行Singleton的构造方法的封装好的操作)
接着是执行 public static int value1=1;
public static int value2=0;
(这两步是执行Singleton类中代码的第3和第4行)
所以最后的结果是 :
value1= 1
value2= 0
然后,我们将Singleton的一行代码:public static Singleton singleton=new Singleton(); 改变下顺序:将它放到静态变量的声明的后面:
public class Singleton {
//public static Singleton singleton=new Singleton();
public static int value1=1;
public static int value2=0;
public static Singleton singleton=new Singleton();
private Singleton(){
value1++;
value2++;
}
public static Singleton getSingleton(){
return singleton;
}
}
value2 =1
如果看明白了之前介绍的类的加载、链接与初始化的讲解的话应该能够明白这两个不一样的输出结果了。其实就是静态代码块的执行顺序不一样。