1.运行时加载优点

提高灵活性,可以在运行时动态加载,连接。例子:面向接口编程,动态绑定实现类(但C++也有动态绑定,说明动态绑定不一定通过运行时加载Class字节码实现,也可能是机器码支持的)

2.编译并在运行时动态加载字节码优点

可在运行时动态获取二进制字节流作为动态代码,比如可以从网络上获取;可以做一个循环,动态从某文件库获取;可以从指定的ClassPath路径获取,比如一个jar包目录

3.与动态类型语言的区别

动态类型语言如JS,可在运行时添加类型属性,方法,在运行时改变类型行为

4.类加载生命周期

加载、验证、准备、解析、初始化、使用、卸载。按这个顺序开始,但交叉执行。验证、准备、解析统称为连接。解析阶段不一定按这个顺序,可以在初始化之后,为了支持上文的动态绑定(运行时绑定)。

5.必须“初始化”(类加载第5阶段)的几种情况(主动引用,有且仅有这些情况时要初始化,初始化钱当然要先“加载”,所以也是必须加载的几种情况)

new实例化对象、读取或设置类static非final字段(final static在编译时存入常量池)、调用类静态方法、类反射调用、初始化一个类时先初始化其父类、虚拟机启动的带main方法的执行主类(虚拟机执行入口)等。

6.不会激发“初始化”的情况(被动引用)

a.引用子类使用其父类的static非final字段(直接定义这个字段的类),只会初始化父类,不会初始化子类。子类是否加载、验证(类加载第1,2阶段),取决于虚拟机具体实现,无规定

b.通过数组定义引用类,不会触发该类初始化。这里触发了一个虚拟机自动生成的代表数组的类的初始化,里面有数组相关属性,比如public的length字段(数组长度)

c.一个类引用另一个类的public static final字段,不会初始化另一个类。该字段引用在编译时进入了前一个类(引用类)的常量池中,编译后就与后一个类完全没关系了。

d.接口初始化:不要求初始化其父类接口,这与类初始化不同。只有使用到父接口比如引用其常量时才会初始化父类接口

7.类加载过程

加载阶段:一个非数组类的加载是开发人员可控性最强的,可以使用系统的引导类加载器,也可使用用户自定义类加载器控制字节流获取方式(下面a所述),即重写loadClass方法。数组类由虚拟机创建,其元素类型由类加载器加载。

a.通过类全限定名获取其字节流,方式:zip/jar/war、网络、运行时计算生成(主要指动态代理生成的"*$Proxy"代理类Class文件)、其他文件生成(如jsp)、数据库读取等

b.字节流静态存储结构转换成方法区运行时数据结构

c.内存中生成代表该类的java.lang.Class对象,作为方法区类数据访问入口

验证阶段:

a.文件格式验证:如魔数开头、主次版本号、常量类型、不符合UTF8的编码

b.元数据验证:语义校验,比如是否有父类、是否继承final类(不允许继承)、是否实现接口、是否覆盖了父类final方法(不允许覆盖)

c.字节码验证:数据流与控制流验证,语义是否合法、符合逻辑。方法体校验:操作数栈数据类型是否与指令码使用类型匹配、指令是否跳到方法体外、方法体内类型转换是否有效

d.符号引用验证:符号引用转为直接引用是在解析阶段进行的,这里是对类自身以外(常量池中各种符号引用)的信息进行匹配校验,比如全限定名是否能找到该类、指定类是否有该符号引用所引用的方法和字段、引用的类、方法、字段访问性(private,protected,public,default)是否可被当前类引用,抛出对应IllegalAccessError、NoSuchMethodError等。

准备阶段:

在方法区将类变量(static)分配内存并设置初始值,通常赋类型零值。如public static int value=123;是赋值为0不是123.赋值123是putstatic指令,在类构造器<clinit>()中,是在初始化阶段才执行的。但public static int value=123;则在准备阶段赋值123.

解析阶段:

将常量池内符号引用替换为直接引用。符号引用:目标不一定已加载入内存。直接引用:直接指向目标的指针、相对偏移量或可间接定位的句柄。引入目标必定在内存中存在。

解析的7类符号引用:类或接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符。

递归加载这些符号引用解析成直接引用后的那些类、父类、接口、父接口,进内存,然后使用直接引用指向它们。

初始化阶段:

执行类构造器<clinit>()方法的过程。

<clinit>()方法由编译器自动搜集所有类变量赋值动作和static{}块合并产生,顺序由源文件中出现顺序决定。static{}块可赋值在其后定义的变量,但不可访问。

public class Test {

  static {

    i = 0;//正常编译

    System.out.println(i);//非法向前引用!!

  }

  static int i = 1;

}

父类<clinit>()方法先于子类<clinit>()执行,由虚拟机调用,而不是子类<clinit>()方法调用。因此父类静态块要优先于子类变量赋值动作。(值为多少的面试题)

static class Parent {

  public static int A = 1;

  static {

    A = 2;

  }

}

static class Sub extents Parent {

  public static int B = A;

}

public static void main(String[] args) {

  System.out.println(Sub.B);

}

B值为2.

接口没有静态块。<clinit>()方法用于变量初始化赋值。不需要先执行父类接口<clinit>()方法,使用时执行。实现接口的类初始化也不需要执行接口<clinit>(),使用时执行。

虚拟机保证<clinit>()方法多线程下安全。如多线程执行,其他线程会阻塞,但退出后其他线程也不会再进入执行。同一个类加载器下(一个类与其加载器一起确定唯一性),一个类型只初始化一次!

JVM类加载机制总结的更多相关文章

  1. JVM基础系列第7讲:JVM 类加载机制

    当 Java 虚拟机将 Java 源码编译为字节码之后,虚拟机便可以将字节码读取进内存,从而进行解析.运行等整个过程,这个过程我们叫:Java 虚拟机的类加载机制.JVM 虚拟机执行 class 字节 ...

  2. JVM总结(四):JVM类加载机制

    这一节我们来总结一下JVM类加载机制.具体目录如下: 类加载的过程 类加载过程概括 说说引用 详解类加载全过程: 加载 验证 准备 解析 初始化 虚拟机把描述类的数据从Class文件加载到内存,并对数 ...

  3. JVM 类加载机制详解

    如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lan ...

  4. Java虚拟机(四):JVM类加载机制

    1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构 ...

  5. JVM类加载机制详解(二)类加载器与双亲委派模型

    在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可 ...

  6. JVM类加载机制(转)

    原文出自:http://www.cnblogs.com/ityouknow/p/5603287.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运 ...

  7. JVM类加载机制详解

    引言 如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 在加载阶段,虚拟机需要完成以下三件事情: 1)通过一个类的全限定名来获取定义此 ...

  8. Android动态加载--JVM 类加载机制

    动态加载,本质上是通过JVM类加载机制将插件模块加载到宿主apk中,并通过android的相关运行机制,实现插件apk的运行.因此熟悉JVM类加载的机制非常重要. 类加载机制:虚拟机把描述类的数据从C ...

  9. Java虚拟机(五):JVM 类加载机制

    一.JVM 类加载机制 JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 1. 加载: 加载是类加载过程中的第一个阶段,这个阶段会在内存中生成一个代表 ...

  10. 深入理解JVM虚拟机6:深入理解JVM类加载机制

    深入理解JVM类加载机制 简述:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 下面我们具体 ...

随机推荐

  1. ListView多种item注意以及自己出现的莫名其妙的错误

    如果ListView不懂,请绕路 1.ListView添加多个item必须用到的两个方法 getViewTypeCount一共有多少种item,我这里写的两种 getItemViewType当前pos ...

  2. [py]python面向对象的str getattr特殊方法

    本文旨在说清楚 类中的 def init def str def getattr 这三个方法怎么用的. 定制输入实例名时输出内容 def __str__会定制输出实例名时候的输出 class Chai ...

  3. PAT 1029 Median[求中位数][难]

    1029 Median(25 分) Given an increasing sequence S of N integers, the median is the number at the midd ...

  4. 申请 Let’s Encrypt 泛域名证书 及 Nginx/Apache 证书配置

    什么是 Let’s Encrypt? 部署 HTTPS 网站的时候需要证书,证书由 CA (Certificate Authority )机构签发,大部分传统 CA 机构签发证书是需要收费的,这不利于 ...

  5. 002-ubuntu安装

    一.安装了ubuntu desktop版本后: 1.进行桥接联网. 2.运行更新:#sudo apt-get update. 3.安装net-tools网络工具包:#sudo apt install ...

  6. Git—使用方法

    1.:插件的安装(eclipse LUNA版本之后已经自动集成,不需要安装插件). * 先打开该网页提供了对应版本的EGit,自己选择相应的版本.(http://wiki.eclipse.org/EG ...

  7. lnmp1.4 安装php fileinfo扩展 方法

    第一步:在lnmp1.4找到php安装的版本 使用命令 tar   -jxvf   php-7.1.7.tar.bz2 解压 第二步: 在解压的php-7.1.7文件夹里找到fileinfo文件夹,然 ...

  8. linux常用命令:Linux 文件属性详解

    Linux 文件或目录的属性主要包括:文件或目录的节点.种类.权限模式.链接数量.所归属的用户和用户组.最近访问或修改的时间等内容.具体情况如下: 命令:  ls -lih 输出: [root@loc ...

  9. python openpyxl 2.5.4 版本 excel常用操作封装

    最近搭框架用的openpyxl 2.5.4版本,之前封装的函数有些提示不推荐使用了,我做了一些更新: 代码: # encoding=utf-8 from openpyxl import load_wo ...

  10. centos7 centos-home 磁盘转移至centos-root下

    1.查看分区 df -h (centos-home和centos-root每人的名字可能不一样) vgdisplay (查看空闲磁盘大小) 2.备份home分区文件 tar cvf /tmp/home ...