• Java中类的加载、连接和初始化


    Java中类的加载、连接和初始化

    类的加载、连接和初始化

    先介绍一下JVM和类

    JVM和类:

    当我们调用Java命令运行某个Java程序时,该命令将会启动一个Java虚拟机进程,不管该Java程序有多么复杂,该程序启动的所有线程,所有变量都处于该Java虚拟机进程里,它们都使用该JVM进程的内存区。当系统出现以下几种情况时,JVM进程将被终止。

    1.       程序运行到最后正常结束;

    2.       程序运行到使用System.exit()或Runtime.getRuntime().exit()代码处结束程序;

    3.       程序运行过程中遇到未捕获的异常或者错误而结束;

    4.       程序所在的平台强制结束了JVM进程。

    从以上看出,当程序运行结束时,JVM进程结束,该进行在内存中的状态将会丢失。如下例:

    // 定义A类含有静态Field a

    public class A

    {

       public static int a = 6;

    }

    // 定义B类创建A类的实例

    public class B

    {

       A a1 = new A();

       a1.a++;

       System.out.println(a1.a);  // 输出7

    }

    // 定义B类创建A类的实例

    public class C

    {

       A a2 = new A();

       System.out.println(a2.a); // 输出6

    }

    C类中输出6的原因是:B与C是两次运行JVM进程,B运行完后对A所做的修改全部丢失,第二次运行JVM时将再次初始化A类。

    类的加载:

    系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类。

    当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化3个步骤来对该类进行初始化,如果没有意外,JVM将会连接完成这3个步骤,所有有时也把这3个步骤统称为类加载或者类初始化。

    类加载指的是将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说,当程序使用任何类时,系统都会为之建立一个java.lang.Class对象

    (每个类是一批具有相同特征的对象的抽象,而系统中所有的类实际上也是实例,它们都是java.lang.Class的实例)。

    类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是所有程序运行的基础,JVM提供的这些类加载器通常被称为系统类加载器,除此之外,我们也可以通过继承ClassLoader基类来创建自己的类加载器,通过使用不同的类加载器,可以从不同来源加载类的二进制数据,通过有如下几种来源。

    1.       从本地文件系统加载class文件;

    2.       从Jar包加载class文件;

    3.       通过网络加载class文件;

    4.       把一个class源文件动态编译,并执行加载。

    类的连接:

    当类被加载之后,系统为之生成一个对应的Class对象,接着将会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中,类连接可分为3个阶段:

    1.       验证:验证阶段用于检验被加载的类是否有正确的内部结构,并和其他类协调一致;

    2.       准备:类准备阶段则负责为类的静态Field分配内存,并设置默认初始值;

    3.       解析:将类的二进制数据中的符号引用替换成直接引用。

    类的初始化:

    在类的初始化阶段,虚拟机负责对类进行初始化,主要就是对静态Field进行初始化,在Java类中对静态Fieldr指定初始值有两种方式:1. 声明静态Field时指定初始值;2. 使用静态初始化块为静态Field指定初始值。如:

    public class Test

    {

       static int a = 5;

       static int b;

       static int c;

       static

    {

       b = 6;

    }

    }// 最终结果 a=5,b=6,c=0

    静态初始化块被当成类的初始化语句,JVM会按这些语句在程序中的排列顺序依次执行它们,如:

    public class Test

    {

       static

    {

       b = 6;

    }

    static int a = 5;

    static int b = 9;

    }// 最终结果 a=5,b=9

    JVM初始化一个类包含如下几个步骤:

    1.       假如这个类还没有被加载和连接,则程序先加载并连接该类;

    2.       假如该类的直接父类还没有被初始化,则先初始化其直接父类(直接父类也依次执行1,2,3 保证类依赖的所有父类都会被初始化);

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

    类初始化的时机:

    1.       创建类的实例,包括使用new操作符来创建,通过反射来创建,通过反序列化的方式来创建;

    2.       调用某个类的静态方法;

    3.       访问某个类或者接口的静态Field,或者为该静态Field赋值;

    4.       通过反射方式来强制创建某个类或接口对应的java.lang.Class对象,例如,Class.forName(“Person”),如果系统还未初始化Person类,则这行代码将会导致该Person类被初始化,并返回Person类对应的java.lang.Class对象;

    5.       初始化某个类的子类;

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

    另外:对于一个Field型的静态Field,如果该Field的值在编译时就可以确定下来,那么这个Field相当于“宏变量“,Java编译器会在编译时直接把这个Field出现的地方替换成它的值,因为即使程序使用该静态Field,也不会导致该类的初始化。

  • 相关阅读:
    JavaScript通过HTML的class来获取HTML元素的方法总结
    HTML5之FileReader接口读取文件
    简单好用用js就可以保存文本文件到本地
    JS获取节点的兄弟,父级,子级元素的方法
    删除window里面删除不掉的文件
    《软件过程改进》练习题
    软件过程改进2016下半年真题及答案
    jquery
    JSP入门
    JAVA方法
  • 原文地址:https://www.cnblogs.com/bendantuohai/p/4769466.html
Copyright © 2020-2023  润新知