类加载器相关内容有很多,大概分以下几个关键点进行学习,

参考链接 https://www.bilibili.com/video/av47756459

目录

概览

JVM与程序的生命周期

类加载器生命周期

加载

连接

初始化

主动使用与被动使用

常量

数组成员变量

反编译

助记符

类加载器准备阶段与初始化阶段

接口的初始化

类实例化

类加载器

JVM自带的类加载器

自定义的类加载器

双(父)亲委托机制

命名空间

类的卸载


概览

类型(类,接口,枚举加载(从硬盘加载到内存),连接(字节码的校验(字节码可以被人为修改)、类之间关系的确定),初始化(静态变量的赋值)均是在程序运行期间完成的

JVM与程序的生命周期

以下几种情况JVM结束生命周期:

(1)执行System.exit()方法

(2)程序正常执行结束

(3)程序运行过程中遇到错误或异常而异常终止

(4)由于操作系统错误引起JVM进程终止

类加载器生命周期

加载

将类的.class 文件中的二进制数据读取到内存中,将其放入运行时数据区的方法区(1.8后有所改动)内,在内存中创建一个java.lang.Class 对象(规范并未明确说明Class对象放置区域,hotspot将其放置在方法区,不同于其他对象放置在中),用来封装类在方法区内的数据结构。

  • 类的加载的最终产品是位于内存中的class对象
  • class对象封装了类在方法区中的数据结构,并向java程序提供了访问方法区内数据结构的接口

加载.class 文件的方式:

— 从本地系统加载

— 通过网络下载

— 从zip等归档文件中加载

— 从专有数据库中加载

从java源文件动态编译为.class 文件(动态代理)

连接

(1)验证:确保加载类的字节码的正确性(2)准备:为类的静态变量分配内存,并将其初始化为默认值(3)解析:把类中的符号引用(间接引用)变为直接引用(使用指针指向内存位置)

初始化

为类的静态变量赋予正确的初始值(将静态变量的声明语句和静态代码块看做类的初始化语句

使用

卸载:从内存中销毁(OSGI)

主动使用与被动使用

在类加载,连接,初始化过程中,java 程序对的使用分为两种:

(1)自动使用(7种)

— 创建类的实例(不是声明)

— 访问某个类或接口的静态变量或给静态变量赋值(子类调用父类的静态变量不会引起子类的主动使用)

— 调用类的静态方法(子类调用父类的静态方法不会引起子类的主动使用)

— 反射

— 初始化类的子类

— JVM启动时被标为启动类(包含main方法)的类(Java Test)

— 从JDK1.7开始的动态语言支持

(2)被动使用

除了主动使用中的7种方法,其余使用java类的方法都称为被动使用,均不会导致类的初始化(不影响加载,连接)

所有java虚拟机实现必须在每个类或接口被java程序“首次主动使用”才初始化。

package test;public class MyTest1 {public static void main(String[] args) {System.out.println(Child.string);}
}class Parent {static String string = "hello";static {System.out.println("Parent static block");}
}class Child extends Parent {static {System.out.println("Child static block");}
}

由于没有主动使用Child类,Child类没有初始化,但是进行了加载!

-XX:+TraceClassLoading 用于追踪类的加载信息并打印,添加至idea配置信息的VM options,即JVM参数(关于VM options,参考:https://blog.csdn.net/upgroup/article/details/81052047)。

常量

对于final属性的成员变量(常量),编译期常量存入调用此常量的方法所在类的常量池中。本质上,调用类并没有直接引用到定义常量的类。因此,并不会触发定义常量的类的初始化。即使删除定义常量的类的class文件也不影响使用,编译过后就完全不需要定义常量的类了。

若是 final 属性的非编译期常量(如 随机数)即 运行期常量,则不同于上述情况。

数组成员变量

建立对象数组,不会主动使用对象类。对于数组实例来说,类型是JVM运行时动态生成的,表示为[***,动态生成的类型其父类型就是Object。

反编译

将已编译的编程语言还原到未编译的状态。java中,就是将.class文件转换成.java文件。使用命令 javap 。(编译使用javac

助记符

ldc, 表示将int,float 或 string 常量值从常量池推送至栈顶

bipush表示将单字节常量(-128 ~ 127)推送至栈顶。

sipush 表示短整型常量推送至栈顶。

iconst_1 (m1 ~ 5)表示将int型常量(m1 ~ 5)推送至栈顶。

anewarray 创建一个引用类型的数组,并将其引用值压入栈顶。

newarray 创建一个指定原始类型的数组,并将其引用值压入栈顶。

类加载器准备阶段与初始化阶段

public class TestClass2 {public static void main(String[] args) {Test test = Test.getTest();System.out.println(test.a);System.out.println(test.b);}
}class Test {static int a;static Test test = new Test();Test() {a++;b++;System.out.println(a);System.out.println(b);}static int b = 0;static Test getTest() {return test;}
}

此例中,类加载器先在准备阶段顺序执行静态代码块,将成员变量赋默认值(a,b为0,test为null),然后再执行类的初始化阶段,a不改变;test执行new Test() ,将a,b值改为1;b初始化值改为0。

简单理解,第一次执行等号左边,第二次执行等号右边。

接口的初始化

由于接口的成员默认都是final的常量,会放置调用此常量的方法所在类的常量池中

不同于类,初始化接口不会引起父接口初始化 (不影响加载)。在初始化一个类时,也不会初始化它实现的接口。但,仍然需要加载。只有当程序首次使用特定接口的静态变量时才会初始化该接口。


public class TestInterface {public static void main(String[] args) {System.out.println(ChildInterface.b);}
}interface ParentInterface {int a = 1 / 0;
}interface ChildInterface extends ParentInterface {int b = new Random().nextInt(10) + 1;
}

这段代码不会报错,即,不会引起ParentInterface 的初始化。若是将接口改为类则会报错。

(能在编译时初始化的,就不延迟到运行时解决)

类实例化

  • 为新的对象分配内存
  • 为实例变量赋默认值
  • 为实例变量赋正确的初始值
  • java编译器为它编译的每一个类都至少生成一个实例初始化方法,在class文件中,这个初始化方法称为<init>方法,针对源代码中的每一个构造方法,java编译器都生成一个<init>方法。

类加载器

JVM自带的类加载器

  • 跟类加载器(Bootstrap) (听着这么熟悉?一个前端开发框架)
  • 扩展类加载器(Extension)
  • 系统(应用)类加载器(System)

自定义的类加载器

  • java.lang.ClassLoader 的子类
  • 定制类加载方式

类加载器并需要该类“首次使用”才加载该类。JVM规范允许类加载器在预料某个类将被使用时,预先加载。若加载出现错误或缺失class文件,将在该类“首次主动使用”时才报告错误。若一直未使用,则不会报错。

双(父)亲委托机制

在双亲委托机制中,各个类加载器按照父子关系形成树形结构。除了启动类加载器(根类加载器)之外,所有类加载器有且只有一个父加载器。

每一个类加载器通过特定的目录进行加载。

首先不自己加载,而是通过自己的父亲加载,父亲又通过父亲的父亲进行加载直到启动类加载器。再自顶向下进行加载,看看到底谁能够加载。

由父加载器加载的类不能访问由子加载器所加载的类。

命名空间

每个类加载器都有自己的命名空间,命名空间由该类加载器及所有父加载器所加载的类组成。

不同的命名空间中类的完整名字可以相同,但是,相同命名空间中不能出现两个相同的完整类名。

因此当实例化多个自己定义的类加载器时,不同的类加载器都会进行加载类。

当在一个类中创建引用对象时,对象所对应的类由加载包含该对象的类的加载器进行加载(同时遵循双亲委托机制)

子加载器所加载的类能够访问父加载器所加载的类。但是,由父加载器加载的类不能访问由子加载器所加载的类。

类的卸载

当MySample类被加载、连接、初始化后,其生命周期就开始了。当代表类Class对象不再被引用,不可触及时,Class对象就会终结其生命周期,MySample类在方法区内的数据就会被卸载,从而结束其生命周期。

一个何时结束其生命周期,取决于代表它的Class对象何时结束其生命周期。

由Java虚拟机自带的类加载器(根类、扩展、系统类加载器)所加载的类,在虚拟机的生命周期中始终不会被卸载。JVM会始终使用这些类加载器,这些类加载器会始终使用它们所加载的类的Class对象,这些Class对象始终是可以触及的。

由用户自定义的类加载器所加载的可以被卸载。

JVM——深入理解类加载器相关推荐

  1. 【深入理解JVM】:类加载器与双亲委派模型

    转载自  [深入理解JVM]:类加载器与双亲委派模型 类加载器 加载类的开放性 类加载器(ClassLoader)是Java语言的一项创新,也是Java流行的一个重要原因.在类加载的第一阶段" ...

  2. Java虚拟机JVM学习05 类加载器的父委托机制

    Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap ...

  3. JVM有哪些类加载器?

    站在Java虚拟机的角度来看,只存在两种不同的类加载器: 1.启动类加载器(Bootstrap ClassLoader),使用C++语言实现,是虚拟机自身的一部分: 2.其他所有的类加载器,由Java ...

  4. JVM系列之类加载器

    前言 上节我们介绍了类加载的时机和过程,对类加载有了个初步的认识,上节我们有不断提到一个东西:类加载器,那么什么是类加载器?又有哪些类加载器?类加载器之间的联系等等一些问题,今天我们将会围绕这些点展开 ...

  5. 【JVM】Java类加载器设计原理(ClassLoader源码解读/ SPI机制/ 绕开双亲委派/ 常见Java虚拟机)

    目录 1. 什么是类加载器 2. 类加载器加载的过程 3. Class文件读取来源 4. 类加载器的分类 5. 那些操作会初始化类加载器 6. 类加载器的双亲委派机制 6.1 双亲委派机制机制的好处 ...

  6. JVM之Java类加载器

    前言 通过对Java类加载机制的了解,可以知道大概流程和各自的功能.其中类加载部分的功能是把类的Class文件读入内存,并创建java.lang.Class对象.这部分功能是由类加载器完成的. 1.类 ...

  7. JVM 自定义的类加载器的实现和使用

    1.用户自定义的类加载器: 要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名 ...

  8. 欧尼酱讲JVM(03)——用户自定义类加载器

    用户自定义类加载器 在Java的日常应用程序开发中,类的加载几乎是由"引导类加载器,扩展类加载器,系统类加载器"这三种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,来 ...

  9. 深入理解JVM(1):类加载器

    文章目录 一.类加载简介 1.简介 2.Java虚拟机与程序的生命周期 3.类的加载.连接与初始化(类加载的最重要的3个阶段) 3.1加载 3.2连接 3.3 初始化 4.类的使用和卸载(类加载的剩余 ...

最新文章

  1. 一种精确从文本中提取URL的思路及实现
  2. 为什么要打jar_生活在西北的兰州人过春节为什么要打太平鼓?
  3. 关于项目过程能力基线的几个讨论
  4. ehcache常用API整理
  5. SpannableStringUtil实现丰富文字效果
  6. Oracle 11g R2的卸载与重装
  7. 数据挖掘:围绕 统计与概率、分类与聚类、检索方法 ,原理演示或应用程序
  8. python 线性拟合 图_python线性拟合
  9. 滴滴这车值不值得上?前Google全球技术总监郄小虎说来来来
  10. cubemx spi 中断_STM32 SPI在使用中断时丢弃数据
  11. VC线程同步技术剖析
  12. 年前的面试经历(二)
  13. Oracle RAC系列之:ASM基本操作维护
  14. Windows7 下载android源码
  15. Matlab画图常用的指令是啥,matlab画图常用命令
  16. Python基础(Day 2)(数值 字符串 布尔 列表)
  17. IAR For MSP430编译后菜单栏丢失解决方法
  18. 微信朋友圈点赞测试用例
  19. windows系统加了一个别的系统!------centos_6 by VMware
  20. 尚医通 (十八)微信登录

热门文章

  1. openwrt 默认ip修改
  2. win10下启动.bat文件闪退问题
  3. 一招解决bat文件执行时cmd命令窗口闪退问题
  4. nubia/努比亚Z5Sn(32GB) root教程_方法
  5. Fiddler 抓包夜神模拟器图文详解
  6. ARM到底是冯诺依曼结构还是哈佛结构
  7. python认证教程_基于 Python+SendCloud 的邮箱认证
  8. Airbnb短租数据分析报告
  9. linux下安装anaconda教程清华源
  10. 43-高级路由:BGP 起源属性:修改为e