先不说JVM,浅谈一下我们的程序。
我们在写完Java代码文件执行后会有一个.class文件,这实际上是javac 命令编译出来的一个文件。java 的口号 write once,run anywhere。这也就是常说的跨平台特性,依赖的也就是JVM。
我们来分析一下这个过程,javac指令把java文件--> class文件,目的是为了让源码能够运行在对应的操作系统上,class文件中应该就是一堆操作系统指令(类似于汇编指令那种),每个操作系统生成的肯定是不一样的,所以这也就是为什么Java可以跨平台。我们可以通过javap 指令实现反汇编,把class文件反汇编成指令。
进入正题~~~
类加载机制
简单来说就是把class文件静态数据加载到java进程的内存中。
装载
通过类加载器classloader进行装载
- 找到想要加载的class文件的位置---- D:\ThreadDemo.class 文件字节流
- 把class文件静态数据内容换成模板信息(在java进程内存去中的保存形式 -- 方法区)
- 会在java进程尼日存取中堆内存创建一个于class文件对应的class对象
链接
- 验证(class文件)
- 保证被加载类的正确性
- 准备
- 为类的静态变量分配内存空间,并为其初始化默认值
- 例如:static int i = 10;会在这个阶段为变量i分配内存空间,并初始化默认值为0
- 解析
- 将符号引用转化为直接引用(指的是常量池中的内容)
初始化
真正的执行类中java程序代码,把上面的i赋值为10
ClassLoader(类加载器)
说完类加载机制,那就来了解一下类加载器吧~
对于不同的class文件进行解析,就要涉及不同的ClassLoader
-
Bootstrap ClassLoader(启动类加载器)
- 加载$JAVA_HOME中jre\lib\rt.jar里所有的class 或-Xbootclasspath选项中指定的jar包
-
Extension ClassLoader(扩展类加载器)
- 加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre\lib\ext\*.jar或-Djava.ext.dir指定目录下的jar包
-
Application ClassLoader(应用程序加载器)
- 加载classpath中指定的jar包及Djava.class.path所制定目录下的类和jar包
-
Custom ClassLoader(自定义类加载器)
- 通过java.lang.ClassLoader的子类自定义加载class属于应用程序根据自身需要自定义的ClassLoader
双亲委派
当一个类收到了类加载的请求,它是会把请求外派给父类。所有的加载请求都应该传送到Bootstrap ClassLoader中,只有当父类反馈没有找到加载的class,子类加载器才会去自己加载。
收到加载请求,层层往上外派,如果没有找到目标class,再一层一层往下让子类去加载