每日一问:讲讲 JVM 的类加载机制
前面给大家讲解了 Java 虚拟的内存结构 以及 Java 虚拟机的垃圾回收机制,我们更加明白了 Java 的内存管理机制,今天我们来讲讲 Java 虚拟机的另外一个高频考点:类加载机制。
JVM 的类加载过程分为加载、验证、准备、解析、初始化 5 个阶段。
加载
加载阶段由类加载器进行负责,类加载器根据一个类的全限定名读取该类的二进制字节流到 JVM 内部,然后转换为一个对应的 java.lang.Class 对象实例;一个类由类加载器和类本身一起确定,所以不同类加载器加载同一个类得到的 java.lang.Class 也是不同的。
验证
验证阶段负责验证类数据信息是否符合 JVM 规范,是否是一个有效的字节码文件。
准备
准备阶段是正式为类变量(static 修饰的变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区进行分配。
这个阶段由两个容易产生混淆的概念需要强调一下,首先是这时候进行内存分配的仅包括类变量,而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在 Java 堆中。其次这里所说的初始值在没有被 final
修饰的时候都是数据类型的零值,只有类似 public static final int value = 1024
这样的情况下才回直接被赋值 123。
解析
解析阶段是虚拟机将常量池内的「符号引用」替换为「直接引用」的过程。
初始化
初始化阶段负责将所有的 static 域按照程序指定操作对应执行(赋值 static 变量,执行 static 块)。
上述阶段通常都是交叉混合允许,没有严格的先后执行顺序。
双亲委派模型
站在 Java 虚拟机的角度讲,只存在两种不同的类加载器:一种是启动类加载器,这个类加载器使用 C++ 语言实现,是虚拟机自身的一部分,另外一种是所有其他的类加载器,这种类加载器都由 Java 语言实现,独立于虚拟机外部,并且全部继承自抽象类 java.lang.ClassLoader
。
双亲委派模型并不是一个强制性的约束模型,而是 Java 设计者们推荐给开发者们的类加载器实现方式。它的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的类加载器中,只有当父加载器反馈自己完成这个加载请求的时候,子加载器才会尝试自己去加载。
使用双亲委派模型来组织类加载器之间的关系,有一个显而易见的好处就是 Java 类随着它的类加载器一起具备了一种带有优先级的层次关系。
采用双亲委派模型的原因
比如黑客定义一个 java.lang.String 类,该 String 类和系统 String 类有一样的功能,只是在某个方法比如 equels() 中加入了病毒代码,并且通过自定义类加载器加入 JVM 中,如果没有双亲委派模型,那么 JVM 就可能误以为黑客编写的 String 类是系统 String 类,导致「病毒代码」最终被执行。而有了双亲委派模型,黑客定义的 java.lang.String 类就用于不会被加载进内存,因为最顶端的类加载器会加载系统的 String 类,最终自定义的类加载器无法加载 java.lang.String 类。
可以通过重写 loadClass() 方法,打破双亲委派模型。
最近的知识比较枯燥,但还是我们所必须了解的。
参考文献:《深入理解 Java 虚拟机》
原文地址:https://www.cnblogs.com/liushilin/p/11042223.html
- 如何将wordpress所有文章批量改为已发布状态
- dedecms提取某栏目及子栏目名称到首页怎么弄
- Bootstrap速学教程之简要介绍
- Ubuntu 安装 JDK8 的两种方式
- git命令-切换分支
- 如何让dedecms文章点击量增加一定的数值
- dedecms自增标签[field:global.autoindex/]的运用
- dedecms调用副栏目文章怎么操作
- 12个非常有用的JavaScript技巧
- 使用JPA中@Query 注解实现update 操作
- 配合dedecms内容模型实现后台输入栏目id前端输出文章列表
- SpringBoot之前端文件管理
- Spring Boot 设置静态资源访问
- IDEA更换主题
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Linux采用双网卡bond、起子接口的方式
- PHP实现字母数字混合验证码功能
- php+pdo实现的购物车类完整示例
- CentOS7怎么执行PHP定时任务详解
- Linux下PHP+Apache的26个必知的安全设置
- linux中ssh免密通信的实现
- 怎么修改CentOS服务器时间为北京时间
- Laravel5.1 框架控制器基础用法实例分析
- Laravel5.1 框架模型软删除操作实例分析
- Laravel 手动开关 Eloquent 修改器的操作方法
- 怎么测试Linux下tcp最大连接数限制详解
- Laravel 5.1 框架Blade模板引擎用法实例分析
- 使用pygame实现垃圾分类小游戏功能(已获校级二等奖)
- Linux 系统下安装JDK1.8的教程详解
- php学习笔记之字符串常见操作总结