• JVM 类的加载机制


    在对类的实例化之前。JVM 一般会先进行初始化

    主要经过如下几个阶段:

      1.加载                      

    类加载的第一阶段,类加载时机有两个:

    1.预加载:当虚拟机启动时,会预加载HOME/lib下的rt.jar里的.class文件

    里面包括java.lang.*java.util.*java.io.*

    还有加载当前启动类并调用main方法

    2.运行时加载:

    首先会去内存中找.class文件有没被加载,没有的话就会按照类的全限定名进行加载

    加载(load)阶段.

    1.1获取类的二进制流文件

    1.2将类的信息、常量、静态变量存到方法区(的运行时常量池)

    1.3在内存中生成该.class文件的java.lang.class对象,作为方法区内这个类的数据访问入口.(HotSpot 比较特殊,他把class对象存到方法区中)

      2.验证                      

    确保.class文件中的字节流信息能够被正确的加载并不会危害到虚拟机的安全

     

      3.准备                      

    类的静态变量分配内存并赋初始值.这时候分配内存的仅仅是静态变量,实例变量会随着类的实例化一起存储在堆内存中

    int声明的默认为0.final修饰变量直接赋值

    例:public static int a=3;

    public static final int b=3;

    在准备阶段a的值是0,而a赋值为3putstatic指令是在程序编译后存放于类构造器<clinit>()方法之中的,所以把a赋值为3的动作将在初始化阶段才会执行,b就直接赋值为3

     

      4.解析                      

    将符号的引用变为直接引用

    这个涉及到编译原理,符号的引用一般有以下三个常量:

    1.类的全限定名

    2.方法的名称和描述符

    3.字段的名称和描述符

    直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接指向目标的句柄

     

     

      5.初始化                                                          

    真正执行java字节码的过程..初始化过程是执行一个类初始化构造器<client>init()的过程

    说白了就是为被static修饰的变量赋于程序指定的值并执行静态代码块

    类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:

    – 创建类的实例,也就是new的方式

    – 访问某个类或接口的静态变量,或者对该静态变量赋值

    – 调用类的静态方法

    – 反射(如Class.forName(“com.shengsiyuan.Test”))

    – 初始化某个类的子类,则其父类也会被初始化

    – Java虚拟机启动时被标明为启动类的类(Java Test),直接使用java.exe命令来运行某个主类

    参考链接:http://www.cnblogs.com/xrq730/p/4844915.html

    类加载器                                                 

    类与类加载器

    虚拟机设计团队把类加载阶段的"通过一个类的全限定名来获取此类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。

    实现这个动作的代码模块称为"类加载器"。类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用却远远不限定于类加载阶段。

    对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。

    这句话表达地再简单一点就是:比较两个类是否"相等",只有在这两个类是由同一个类加载器加载的前提下才有意义,否则即使这两个类来源于同一个.class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,这两个类必定不相等。

    上面说的"相等",包括代表类的.class对象的equals()方法、isAssignableFrom()方法、isInstance()方法的返回结果,也包括使用instanceof关键字做对象所属关系判定等情况。

     

    双亲委派模型

    最后讲一下双亲委派模型,其实上面的类加载器模型图就是一个双亲委派模式的图,这里把它再讲清楚一点。

    双亲委派模型是在JDK1.2期间被引入的,其工作过程可以分为两步:

    1、如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此。

    2、只有当父加载器反馈自己无法完成这这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载

    所以,其实所有的加载请求最终都应该传送到顶层的启动类加载器中。双亲委派模型对于Java程序的稳定运作很重要,因为Java类随着它的加载器一起具备了一种带有优先级的层次关系。

    例如java.lang.Object,存放于rt.jar中,无论哪一个类加载器要去加载这个类,最终都是由Bootstrap ClassLoader去加载,因此Object类在程序的各种类加载器环境中都是一个类。

    相反,如果没有双亲委派模型,由各个类自己去加载的话,如果用户自己编写了一个java.lang.Object,并放在CLASSPATH下,那系统中将会出现多个不同的Object类,Java体系中最基础的行为也将无法保证,应用程序也将会变得一片混乱。

  • 相关阅读:
    jsp初识
    OAuth2.0
    微服务参考案例
    3.0技术架构落地
    聚合层改进意见-彭泉锋-2018.10.31
    图片分步加载(解决图片load函数刷新不加载问题)
    IOS iframe宽高问题(来至stackoverflow)
    jquery easy-ui 分页插件的运用(给td添加事件,获取汇总内容)
    JS 获取当前日期(yy-mm-dd HH-MM-SS)
    JQ iframe 子元素找父级 的元素
  • 原文地址:https://www.cnblogs.com/zewen/p/7061232.html
Copyright © 2020-2023  润新知