类加载器深入解析与阶段分解

对于搞Java的程序员来说,一提到JVM就会望闻生畏,感觉掌握不掌握对于实际的开发没有任何意义,但是!在如今要想去面试一个高级或者资资职位的Java程序开发,JVM是广大面试官特别喜欢拿来“装逼”问你的,其实也能理解,java程序是运行在JVM之中的,对它如果完全不了解也配是一个合格的Java程序员,而如今并非只有Java是运行在JVM之上的,对于做Android开发的另一门语言---kotlin,它也是基于JVM的,所以说接下来准备啃一啃这个硬骨头。

对于JVM来说它涉及到的知识体系可谓相当相当的庞大,要想完全都将其掌握也是不现实的,所以主要是将一些非常核心的东西研究透以便在面试官想装逼之时你也可以进一步装逼,或者这样说:先打好一个JVM学习的基础,以便为将来想进一步深入它做一个扎实的基础功,消除谈虎色变的境态,好了!下面正式开启学习之路。

对于"类加载器"应该都听说过,在实际程序中也遇到过类似的关键类,典型的就是"ClassLoader",所以学习JVM从研究透类加载器开始,对于这次的开篇学习而言都是纯理论,而学习JVM的一大特点就是理论特别多而且也特别特别的重要,不像学习其它的一个应用形的框架以实际编码为主,当然纯天理论的东东是学过立马就会忘掉的,所以肯定得要有实际的代码对理论进行论证,所以还是以理论+实践的方式来学习JVM,注意:学习JVM理论一定得要一个个字去揣摩。

类加载【ClassLoading】:

  • 在Java代码中,类型的加载、连接与初始化过程都是在程序运行期间完成的。
    这句话涉及到两个很重要的概念:
    ①、其中标红的"类型"指的是我们定的Class、Interface、Enum,注意:在类加载这个阶段并未涉及到任何对象的概念。
    ②、类加载过程是在程序运行期间完成的,因为这个特性使得我们程序员可以做一些创新的东东,具体的体现待未来再来发掘。
    而其中谈到了"加载、连接与初始化"三个过程, 从字面意思来看貌似是比较好理解的,但是呢其实这里面又可以细分很多子阶段,这个在未来的学习中再来体会,下面对这三个过程的意思大概的阐述一下:
    “类型的加载”:用一个【注意:并不是唯一】比较典型的场景来理解:将已经编译好的.class字节码文件从磁盘里面加载到内存里面,这就是加载所有完成的事情。
    “连接”:用一个比较简洁的话来描述:将类与类之间的关系给确定好,并且对于字节码的一些验证、校验都是在这个阶段进行的,因为最后加载的一定是字节码,只有字节码真正的木有问题才能够最后由JVM去执行,那如果字节码产生了问题很显然JVM就拒绝执行,那问题来了:很显然这个.class的字节文件是由编译器生成的呀,又不是人为生成的,那怎么会有问题呢?因为字节码文件可以通过一些特殊的工具进行修改的, 所以既然是可能被篡改那肯定是需要有校验过程滴。
    “初始化”:指的是对类型中的一些静态变量进行赋值。
  • 提供了更大的灵活性,增加了更多的可能性。
    正因为是类加载是在运行期完成的,这也是上述描述的结果,而“增加了更多的可能性”指的就是为一些有创意的研发人员提供了一些拓展,可以基于JVM提供了极强的灵活性去实现一些之前可能很难实现的一些功能。

类加载器【ClassLoader】深入剖析:

这个类在实际开发中也经常能够看到,看着挺高级的,在剖析之前先对“类加载器”的含义做一个简单说明:Java里面每一个类型比如:java.lang.String、java.util.Date,它最终的数据结构被纳入到JVM的管辖范围之内,也就是进入到了内存当中,而每一个类型都会被进入到JVM的内存当中,那怎么进入的呢?这也就由类加载器来完成的,换言之,类加载器就是加载类的工具,下面来看一下JVM与程序的生命周期:

在如下几种情况下,JVM将结束生命周期,因为JVM其实就是一个进程当然也就存在会结束的可能:

  • 执行了System.exit()方法。
  • 程序正常执行结束。
  • 程序在执行过程中遇到了异常或错误而异常终止。
  • 由于操作系统出现错误而导致JVM进程终止。【这种情况是我们无能为力的,了解一下既可】

类的加载、连接与初始化【在上面已经有说明,再细化一下】:

  • 加载:查找并加载类的二进制数据。
  • 连接:
    ①、验证:确保被加载的类的正确性。
           使得加载的类的字节码文件都是符合JVM对于字节码格式的要求,关于Class文件的格式在后面也会学到。
    ②、准备:为类的静态变量分配内存,并将其初始化为默认值
           其中对重点的标红了,为啥是静态变量呢?因为这还是类的加载阶段木有生成对象,当然只有静态变量喽,另外此时给静态变量初始的值是默认值,拿代码来说明:

    最终结果我们都知道1肯定是赋值给了静态变量a了,然而中间过程并不是这么直接的,而对于这个准备阶段而言会为这个a分配内存,并且此时赋值给它的值为默认值0,而非1,而1的赋值是在后面的阶段才进行的【也就是下面的初始化接段做的事】,这个需要特别的注意。

    ③、解析:把类中的符号引用转换为直接引用
            这里涉及到了两个概念:
                     符号引用:可以理解为一种间接的引用方式,通过一个符号的表示来引用,比如说一个类里面的方法引用了另外一个类。
                     直接引用:直接将方法通过指针的方式指向了目标的对象的内存地址,这样一下就能找到该方法。

  • 初始化:为类的静态变量赋予正确的初始值。
             
    也就是上面准备阶段说到的只有在这个阶段才是给静态变量赋予的是我们期望的值。

【说明】:其实完整的过程是有五个,只是说另外两个过程不是那么重要,如下面。

类的使用与卸载【了解既可,也就是完整五个阶段的不太重要的两个阶段】:

  • 使用:
         这个就不多说了,就是使用类嘛。比如:用类创建对象,然后对象调用里面的方法。这也是我们开发时天天与之打道的地方。
  • 卸载
         class文件加载到内存之后就驻留在内存里面啦,而这个内存还可以被销毁掉,这就叫类的卸载,如果类被卸载之后就不能再用这个类创建对象了,貌似在开发中基本上接触不到类的卸载这个概念的,

posted on 2018-02-13 22:34  cexo  阅读(782)  评论(1编辑  收藏  举报

导航