• Java基础03-类的加载过程03(解析、再说初始化)


    注:基于《Java高并发编程详解-汪文君》、《深入理解JVM高级特性与最佳实践-周志明》,以学习为目的,加上自身理解、验证。作为笔记,为加深印象,做到不复制,不粘贴。欢迎,大家一起交流学习。

    上回最后部分说到类加载阶段过程中关于类接口、字段的解析流程。那么今天就接着上回的内容,从类方法、接口方法的解析开始继续往下学习。

    类方法的解析

    类方法和接口方法不同,类方法可以直接使用该类进行调用,但是接口方法必须要有相应的实现类继承才能够进行调用。

    1.如果在类的方法表中,发现class_index中索引的Resolve是一个接口的话,而不是一个类,直接会返回错误。

    2.在Resolve类中,查找是否有方法描述和目标方法完全一致的方法,如果没有,则继续向其父类中去找,否则直接返回这个方法的引用

    3.如果在父类中一直没有找到,就意味着查找失败了,会抛出NoSuchMethodErrorException。如果在当前类或者父类中找到了和目标方法一致的方法,但是它是一个抽象的类,会抛出AbstractMethodErrorEcveption。

    当然,在类方法查找的过程中,也存在着大量的校验和验证。

    接口方法的验证

    接口可以定义方法,也可以去继承其他接口。

    1.在接口方法表中发现class_index中索引的Resolve是一个类而不是接口,会直接报错。理论上来说,方法接口表中和类接口表中所容纳的类型应该是不一样的。从常量池中有Contant_Methodref_info和Contant_IntefaceMethodredInfo两个不同的类型也可以看出来。

    2.接口方法的查找和类方法类似,子类到父类,自上而下。

    类的初始化阶段-类加载过程中最后一个阶段

    在这个阶段中,最重要的一件事,执行<clinit>()(class_initialize)方法,所有的类变量都会赋予正确的值,也就是程序所制定的值。

    <clinit>()方法包含在生成的class文件中,在编译阶段生成。它包含了所有类变量的赋值动作和静态块的执行代码。编译器收集的顺序是由执行语句在源文件中的出现顺序决定的。注意:该方法能够保证顺序性。另外,静态块只能对后面的静态变量进行赋值,单数不能够访问。

    注:

    1.如果在一个类或者中没有静态代码块,也没有静态变量,那么它就没有<clinit>()方法。

    2.<clinit>()方法只能够被虚拟机所执行,类主动使用后会去调用这个方法。

    3.JVM保证了该方法在多线程的执行环境下的同步语义,所以在Java的单例模式一文中,看到的Holder实现单例模式是一种比较适合的方式。

    类加载过程总结

    随着java的不断发展,jvm不断升级,类加载可能会变。但无论怎么变,还是会以class二进制文件加载,连接,类的初始化进行下去。最后,再看下在类加载过程中的这段代码,作为这一个阶段学习的结束。

     1 public class Simple {
     2 
     3     // 1.
     4     private static int x = 0;
     5     private static int y;
     6 
     7     private static Simple instance = new Simple(); // 2.
     8 
     9     private Simple() {
    10         x++;
    11         y++;
    12     }
    13     
    14     public static Simple getInstance() {
    15         return instance;
    16     }
    17 
    18     public static void main(String[] args) {
    19         Simple instance = Simple.getInstance();
    20         System.out.println(instance.x);
    21         System.out.println(instance.y);
    22     }
    23 
    24 }

    说明:

    1. 加载二进制文件后,进入到连接阶段,类变量x, y,instance赋予对应的初始值,即 x = 0, y = 0, instance=null,进入到解析阶段。
    2. 解析阶段过后,到初始化阶段,为每一个类变量赋值程序文件中对应的指定值。也就是执行<clinit>方法的过程。执行过后x = 0, y = 0, instance=new Simple()。
    3. 接下来,非常熟悉,在new()的过程中,执行Simple类的构造方法,结果为 x = 1; y = 1。至此,类的加载完成。
  • 相关阅读:
    linux每日命令(31):tar命令
    Django——model基础
    Django——模板层(template)(模板语法、自定义模板过滤器及标签、模板继承)
    Django
    linux每日命令(30):Linux 用户及用户组相关文件、命令详解
    linux每日命令(29):chown命令
    20170430深圳Meetup
    静态库嵌套引用问题
    JD-Store购物网站复盘——20170312
    20170305Meetup Git、heroku drop db
  • 原文地址:https://www.cnblogs.com/sunl123/p/11110685.html
Copyright © 2020-2023  润新知