JVM java类的装载、链接、初始化

来源:互联网 发布:tcp ip网络协议栈 编辑:程序博客网 时间:2024/04/29 02:52

java从源文件到程序运行需要经历两个步骤

  • .java文件经过最初的编译成为.class字节码,成为机器识别的二进制语言。
  • .class文件由JVM解释成所对应不同的硬件平台操作系统能够执行的代码。
    (编译器是与平台无关,编译生成的中间码也与平台无关(一次编译,到处运行),中间码再由解释器解释执行,解释器是与平台相关的,也就是不同的平台需要不同的解释器.java程序也通过运行在不同jvm上实现跨平台)
解释有以下的三个步骤
  • 装载:通过classLoader 把字节码文件装载到内存中,程序只有加载到内存才能运行。创建对应类的实例,在堆区建立一个java.lang.Class对象。
  • 链接:链接又分为以下三个步骤
    • 验证:验证内存中的字节码文件是否符合jvm规范,符合规范的文件才能够在javm下运行
    • 准备: 将类的成员变量分配内存空间,初始化默认值。(虽然类的变量有初始值,但此时不会对变量进行初始化)(对于类的成员变量,不管程序有没有显式的进行初始化,Java虚拟机都会先自动给它初始化为默认值。但是局部变量,java虚拟机就不会对他进行默认初始化,所以声明时必须对它进行显示初始化)
    • 解析:为类、接口、方法、成员变量的符号引用定位直接引用。
  • 初始化:按照顺序执行静态代码块,将类的静态变量赋予正确的初始值(这个初始值是显示初始化的值,没有显示初始化的值还是系统为他分配的默认值),只有当类第一次主动使用时(new,反射,初始化子类等…)才会去初始化类
    1. 假如这个类还没有被加载和连接,那就先进行加载和连接。初始化一定在加载链接之后
    2. 如果父类还没有被初始化,那就先初始化父类。(接口的初始化,不会引起父类接口的初始化)
    3. 依次执行初始化语句。
      代码思考:
class Singleton {         public static Singleton singleton = new Singleton();         public static int a;         public static int b = 2;         private Singleton() {             super();             System.out.println("构造前"+a+"--"+b);        a++;             b++;         }         public static Singleton GetInstence() {             return singleton;         }     }     public class MyTest {         /**         * @param args         */        public static void main(String[] args) {             Singleton mysingleton = Singleton.GetInstence();             System.out.println(mysingleton.a);             System.out.println(mysingleton.b);         }     }    

一般都会得到的结论就是,a=1,b=3。但是正确的 运行完后答案是【构造前0–0,a=1,b=2。】
为什么呢?当你用到这个类时( Singleton mysingleton = Singleton.GetInstence(); ) 你才会去初始化这个类,初始化是有先后顺序的,根据代码首先初始化singleton对象( static Singleton singleton = new Singleton(); ),这个对象的变量还是jvm赋给的默认值,因为还没对a,b进行初始化(所以 a=0,b=0)。随后再去初始化a,b。 就将b设为了初始值0。
—如果将static Singleton singleton = new Singleton();的初始化放到a、b初始化之后,那么输出的结果是【构造前0–2,a=1,b=3】

0 0
原创粉丝点击