• 技术文章 >Java >java教程

    详解JAVA类加载机制(推荐)

    黄舟黄舟2016-12-14 17:30:40原创579
    JAVA源码编译由三个过程组成:

    1、源码编译机制。

    2、类加载机制

    3、类执行机制

    我们这里主要介绍编译和类加载这两种机制。

    一、源码编译

    代码编译由JAVA源码编译器来完成。主要是将源码编译成字节码文件(class文件)。字节码文件格式主要分为两部分:常量池和方法字节码。

    二、类加载

    类的生命周期是从被加载到虚拟机内存中开始,到卸载出内存结束。过程共有七个阶段,其中到初始化之前的都是属于类加载的部分

    加载----验证----准备----解析-----初始化----使用-----卸载

    系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类,当运行某个java程序时,会启动一个java虚拟机进程,两次运行的java程序处于两个不同的JVM进程中,两个jvm之间并不会共享数据。

    1、加载阶段

    这个流程中的加载是类加载机制中的一个阶段,这两个概念不要混淆,这个阶段需要完成的事情有:

    1)通过一个类的全限定名来获取定义此类的二进制字节流。

    2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

    3)在java堆中生成一个代表这个类的Class对象,作为访问方法区中这些数据的入口。

    由于第一点没有指明从哪里获取以及怎样获取类的二进制字节流,所以这一块区域留给我开发者很大的发挥空间。这个我在后面的类加载器中在进行介绍。

    2、准备阶段

    这个阶段正式为类变量(被static修饰的变量)分配内存并设置类变量初始值,这个内存分配是发生在方法区中。

    1、注意这里并没有对实例变量进行内存分配,实例变量将会在对象实例化时随着对象一起分配在JAVA堆中。

    2、这里设置的初始值,通常是指数据类型的零值。

    private static int a = 3;
    这个类变量a在准备阶段后的值是0,将3赋值给变量a是发生在初始化阶段。

    3、初始化阶段

    初始化是类加载机制的最后一步,这个时候才正真开始执行类中定义的JAVA程序代码。在前面准备阶段,类变量已经赋过一次系统要求的初始值,在初始化阶段最重要的事情就是对类变量进行初始化,关注的重点是父子类之间各类资源初始化的顺序。

    java类中对类变量指定初始值有两种方式:1、声明类变量时指定初始值;2、使用静态初始化块为类变量指定初始值。

    初始化的时机

    1)创建类实例的时候,分别有:1、使用new关键字创建实例;2、通过反射创建实例;3、通过反序列化方式创建实例。

    new Test();
    Class.forName(“com.mengdd.Test”);

    2)调用某个类的类方法(静态方法)

    Test.doSomething();

    3)访问某个类或接口的类变量,或为该类变量赋值。

    int b=Test.a;
    Test.a=b;

    4)初始化某个类的子类。当初始化子类的时候,该子类的所有父类都会被初始化。

    5)直接使用java.exe命令来运行某个主类。

    除了上面几种方式会自动初始化一个类,其他访问类的方式都称不会触发类的初始化,称为被动引用。

    1、子类引用父类的静态变量,不会导致子类初始化。

    public class SupClass
    {
     public static int a = 123;
     static
     {
      System.out.println("supclass init");
     }
    }
    public class SubClass extends SupClass
    {
     static
     {
      System.out.println("subclass init");
     }
    }
    public class Test
    {
     public static void main(String[] args)
     {
      System.out.println(SubClass.a);
     }
    }

    执行结果:

    supclass init
    123

    2、通过数组定义引用类,不会触发此类的初始化

    public class SupClass
    {
     public static int a = 123;
     static
     {
      System.out.println("supclass init");
     }
    }
    public class Test
    {
     public static void main(String[] args)
     {
      SupClass[] spc = new SupClass[10];
     }
    }

    执行结果:

    3、引用常量时,不会触发该类的初始化

    public class ConstClass
    {
     public static final String A= "MIGU";
     static
     {
      System.out.println("ConstCLass init");
     }
    }
    public class TestMain
    {
     public static void main(String[] args)
     {
      System.out.println(ConstClass.A);
     }
    }

    执行结果:

    MIGU

    用final修饰某个类变量时,它的值在编译时就已经确定好放入常量池了,所以在访问该类变量时,等于直接从常量池中获取,并没有初始化该类。

    初始化的步骤

    1、如果该类还没有加载和连接,则程序先加载该类并连接。

    2、如果该类的直接父类没有加载,则先初始化其直接父类。

    3、如果类中有初始化语句,则系统依次执行这些初始化语句。

    在第二个步骤中,如果直接父类又有直接父类,则系统会再次重复这三个步骤来初始化这个父类,依次类推,JVM最先初始化的总是java.lang.Object类。当程序主动使用任何一个类时,系统会保证该类以及所有的父类都会被初始化。

    以上所述是小编给大家介绍的JAVA类加载机制(推荐),希望对大家有所帮助, 更多相关文章请关注PHP中文网(m.sbmmt.com)! !


    php入门到就业线上直播课:查看学习

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。

    前端(VUE)零基础到就业课程:点击学习

    清晰的学习路线+老师随时辅导答疑

    自己动手写 PHP MVC 框架:点击学习

    快速了解MVC架构、了解框架底层运行原理

    专题推荐:JAVA类,加载机制
    上一篇:Iterator和ListIterator的不同使用方法 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• Java数据结构之单链表与OJ题• 详细介绍Java正则表达式之单字符匹配和预定义字符• 实例详解Java顺序表和链表• Java总结分享之反射、枚举、Lambda表达式• 深入分析Java的序列化与反序列化
    1/1

    PHP中文网