java类加载机制,再也不怕面试官的刁难
上一篇我们详细的讲解了java 虚拟机的内存模型(),并且知道了我们写的代码分别是怎么存在JVM的哪个内存区域中。今天我们来看另一个重要的问题,类加载机制的核心知识,这个知识也是面试经常问到的。
01
我们的java代码是怎么运行起来的?
我们在写好java代码之后,都是先进行打包,打成jar包或者war包,最后丢到服务器上启动JVM进程就能运行了。大概是下面这样的一个过程。
那么,现在我们就来看看这些类是怎么被加载到JVM中,它的加载机制又是什么样的
02
java类什么时候会被加载
我们写的java类,从被加载到使用,一般会经历下面几个步骤:
加载-->验证-->准备-->解析-->初始化-->使用-->卸载
我们首先就要知道,我们的类是什么时候被加载进JVM的?其实,我们有一定经验后就已经知道了,类在被使用的时候就会被加载进JVM中。
public class MyTest {
public static void main(String[] args) {
Study study = new Study();
study.studyJava();
}
}
//
public class Study {
public void studyJava() {
System.out.println("This is Java");
}
}
我们来看上面代码,当我们启动JVM运行到有main()方法的时候,这个时候MyTest.class这个类就会被加载进来,然后运行到有一个new Study() 的时候,发现需要实例化一个Study对象,就会去class文件找到study类加载进来,如下图
03
类连接过程
类的连接主要是指类验证、准备以及初始化的过程。这些我们暂时只用先了解下功能就行,一般在我们开发中不怎么会用到。
- 验证阶段:是指我们加载进来的class文件是否合法,有没有被篡改等
- 准备阶段:就是将我们加载来的类分配相应的内存空间,以及给变量指定初始值等,例如,private int type; 这种的
- 解析阶段:这个主要是将符号引用替换为直接引用的过程。
最为核心的阶段就是初始化,所以,我们来单独说一下初始化。
老规矩,我们先来看一段代码:
public class Study {
public static int strategyType = Configuration.getInt("config.strage.type");
}
上面我们说过在类的准备阶段,是分配内存空间以及给出初始化值的,然而我们现在的这个Configuration.getInt("config.strage.type") 在准备阶段会不会执行这段代码呢?其实是不会执行的,这里只会分配内存和给个初始值“0”,Configuration.getInt("config.strage.type") 是在初始化阶段进行执行的,然后再将结果赋值给strategyType的,还有就是我们经常写的static{}代码块也是在初始化阶段进行执行的。
04
什么时候会初始化一个类
现在我们已经弄明白了什么是初始化操作了,接下来我们来看看初始化的相关规则:
在new一个对象的时候,这个时候就会触发类的加载到初始化的全过程。
包含main()方法的类,需要立马初始化。
如果在初始化一个类时,发现他的父类没有进行初始化,那么就得先初始化父类。
类加载器以及双亲委派机制
通过上面的学习,我们已经很清楚了类的加载到初始化的整个过程,那么下面我们就需要去了解类加载器了,只有具备类加载器,上面那些过程才能得以实现。在我们java中主要有如下四种类加载器:
1,Bootstrap ClassLoader 启动类加载器
这个主要是用来加载我们安装在机器上JDK目录的核心类,即在我们java 目录的lib包里的各种jar包,我们启动JVM的时候,第一步就是加载这lib里面的类。
2,Extension ClassLoader 扩展类加载器
这个也是加载我们jdk默认的扩展类,在我们java目录的libext目录里面的各种jar包。
3,Application 应用程序类加载器
这个类加载器就是加载我们在classPath 环境变量指定的路径的类,也就是我们自己开发出来的各种类。
4,自定义类加载器
自定义就是根据自己的需要,设计一种自己的加载器去加载我们写的程序,和上面3种是互斥的。
双亲委派机制
上面我们将我们java里面的四大类加载器进行了梳理,并且知道了每个加载器各是加载什么内容的,那么最后我们还需要知道这些类加载器是怎么配合运行我们的系统的。
其实,JVM的类加载器是有亲子层级关系的,自上到下分别是启动类加载器、扩展类加载器、应用程序类加载器乃至最后一层是自定义类加载器。这就是一个双亲委派的机制。
怎么进行委派
就是指如果咱们的应用程序类加载器需要加载一个类的时候,它第一步就是先找它的父类加载器去加载,直到最顶层的类加载器。如果父类加载器在自己负责的范围内并未找到这个类的话,就会把加载的权利让给自己的子类去加载
我们还是来用一个例子来说明下吧,比如我们要加载Study这个类的时候:
- 应用程序类加载器会去找他的父亲扩展类加载器去帮它加载这个Study这个类。
- 扩展类加载器这个时候也会去请求他自己的父亲启动类加载器去帮忙加载Study这个类。
- 启动类加载器找了一圈发现这个Study并不在他的加载范围内,然后,就说不在我这儿,你自己去找。
- 扩展类就自己找,也找了一圈,仍然是没找到,就会下发他的儿子,你自己的类,你自己找去
- 应用程序类加载器这个时候就会自己找Study这个类,然后给加载进JVM中
下面我们来通过一张图来整体认识下类的加载过程以及双亲委派机制
总结,今天我们将我们常用的JVM类加载机制以及他的双亲委派模型进行了详细的讲解,大家只要认真学习了,相信,在我的工作开发中会更加的清晰明朗,同时,对于面试官的刁难也会有一套自己的应对方案。
下一篇预告:聊聊分库分表的专题
关于架构师修炼
本号旨在分享一线互联网各种技术架构解决方案,分布式以及高并发等相关专题,同时会将作者的学习总结进行整理并分享。
更多技术专题,敬请期待
- HDU 3032 Nim or not Nim?(Multi-Nim)
- POJ 2311 Cutting Game(二维SG+Multi-Nim)
- js去掉html标签和去掉字符串文本的所有的空格
- php操作memcache的使用测试总结
- linux awk命令详解
- php str_split 解决中文
- PHP汉字转拼音函数
- 51NOD 1185 威佐夫游戏 V2(威佐夫博弈)
- HDU 1527 取石子游戏(威佐夫博弈)
- PHP文件操作类
- Linux添加/删除用户和用户组
- 次小生成树
- HDU 4786Fibonacci Tree(最小生成树)
- HDU 1847 Good Luck in CET-4 Everybody!(找规律版巴什博奕)
- 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 文档注释
- 实例讲解PHP中使用命名空间
- PDO::errorCode讲解
- PDO::errorInfo讲解
- PHP的PDO大对象(LOBs)
- PHP抽象类与接口的区别详解
- PDO::exec讲解
- 使用keras框架cnn+ctc_loss识别不定长字符图片操作
- PHP实现的策略模式示例
- 浅谈pytorch中torch.max和F.softmax函数的维度解释
- 用PHP的反射实现委托模式的讲解
- PHP时间函数使用详解
- python批量处理多DNS多域名的nslookup解析实现
- PHP单例模式数据库连接类与页面静态化实现方法
- pytorch 常用函数 max ,eq说明
- 解析python 中/ 和 % 和 //(地板除)