• 7.1 类型装载、连接与初始化


    Java虚拟机通过装载、连接和初始化一个java类型,使该类型可以被正在运行的java程序所 使用、其中,装载就是把二进制形式的Java类型读入Java虚拟机中;而连接就是把这种已经读人 虚拟机的二进制形式的类型数据合并到虚拟机的运行时状态中去。连接阶段分为三个子步骤-验证、准备和解析。“验证”步骤确保了Java类型数据格式正确并且适于java虚拟机使用;

    而“准备”步骤则负责为该类型分配它所需的内存,比如为它的类变量分配内存。“解析"步骤 则负责把常量池中的符号引用转换为直接引用。虚拟机的实现可以推迟解析这一步,它可以在 当运行中的程序真正使用某个符号引用时再去解析它(把该符号引用转换为直接引用)。当验证、 准备和(可选的)解析歩骤都完成了时.该类型就已经为初始化做好了准备。在初始化期间, 都将给类变量赋以适当的初始值。整个过程如图7-1所示。


    就像在图7-1中所看到的那样,装载、连接和初始化这三个阶段必须按顺序进行。惟—的例外就是连接阶段的第三步——解析,它可以在初始化之后再进行。

    在类和接口被装载和连接的时机上,Java虚拟机规范给实现提供了一定的灵活性。但是它严 格地定义了初始化的时机。所有的Java虚拟机实现必须在每个类或接口首次主动使用时初始化。 下面这六种情形符合主动使用的要求。
    •当创建某个类的新实例时(或者通过在字节码中执行new指令;或者通过不明确的创建、 反射、克隆或者反序列化)。

    •当调用某个类的静态方法时(即在字节码中执行invokestatic指令时)。

    •当使用某个类或接口的静态字段,或者对该字段陚值时(即在宇节码中,执行getstatic或 putstatic指令时),用final修饰的静态字段除外,它被初始化为一个编译时的常量表达式。

    •当调用Java API中的某些反射方法时,比如类Class中的方法或者java.lang.reflect包中的类的方法。

    •当初始化某个类的子类时(某个类初始化时,要求它的超类已经被初始化了 )。

    •当虚拟机启动时某个被标明为启动类的类(即含有main ()方法的那个类)。

    除上述这六种情形外,所有其他使用Java类型的方式都是被动使用,它们都不会导致java类型的初始化。本章稍后会给出几个例子以说明主动使用和被动使用的区别。

    在上面我们曾提到,任何一个类的初始化都要求它的超类在此之前已经初始化了。以此类推,该规则就意味着某个类的所有祖先类必须在该类之前被初始化。然而,对于接口来说,这条规则并不适用。只有在某个接口所声明的非常量字段被使用时,该接口才会被初始化,而不会因为实现这个接口的子接口或类要初始化而被初始化。因而,任何一个类的初始化都要求它 的所有祖先类(而不是祖先接口)预先被初始化。而一个接口的初始化,并不要求它的祖先接 口预先被初始化。

    “在首次主动使用时初始化“这个规则直接影响着装载、连接和初始化类的机制。在首次 主动使用时,其类型必须被初始化。然而,在类型能被初始化之前,它必须已经被连接了,而 在它能被连接之前,它必须已经被装载了。Java虚拟机的实现可以根据需要在更早的时候装载以 及连接类型,没有必要一直要等到该类型的首次主动使用才去装载和连接它。无论如何,如果 一个类型在它的首次主动使用之前还没有被装载和连接的话,那它必须在此时被装载和连接,这样它才能被初始化。

  • 相关阅读:
    最小的k个数
    数组中出现次数超过一半的数字
    字符串的排列
    二叉搜索树与双向链表
    复杂链表的复制
    二叉树中和为某一值的路径
    centos7安装wrk
    【胡思乱想】JNI与线程池的维护
    【胡思乱想】命令模式中,命令对象如何解耦Invoker和Receiver
    【胡思乱想】命令模式 与 Thread Runnable
  • 原文地址:https://www.cnblogs.com/mongotea/p/11979538.html
Copyright © 2020-2023  润新知