- 什么是虚拟机?
从字面意思上来看,顾名思义即使一台虚拟的计算机,用来执行虚拟的计算机指令,从大体上来看,虚拟机一般分为两种。一种是系统虚拟机,另外一种是程序虚拟机。
系统虚拟机:代表为VMware
程序虚拟机:代表为JVM(java虚拟机)
- JVM的作用?
负责将字节码加载到内存在中(运行时数据区)
将字节码转换为机器码,在各个系统中执行
负责存储数据
垃圾回收
- JVM的整体组成部分?
类加载
运行时数据区(堆、java虚拟机栈、方法区、程序计数器、本地方法栈)具体了解请点击(java运行时区域分布)
执行引擎(将字节码转换为机器码)
本地方法接口
垃圾回收
程序将java代码首先转换为class文件(字节码),jvm通过类加载器用IO的方式将字节码加载到内存中(运行时数据区),但是字节码不能被底层系统所识别,所以需要特定的命令解析器(执行引擎)将字节码翻译成为底层系统指令交给CPU进行执行,在执行的过程中会调用到其他语言的接口(本地方法接口)来实现功能的实现。
- 类加载
- 类加载器的作用?
负责从硬盘|网络中加载节码信息
将节码信息加载到内存(运行时数据区)中
- 类加载过程?
- 加载
通过类名(地址)获取此类的二进制字节流
将这个字节流所代表的静态存储结构转换为方法区的运行结构
在内存中生成一个代表这个类的java.lang.Class对象,作为这个类的各种数据的访问接口
- 链接
验证:
对字节码文件的格式进行验证,文件是否被污染
对基本的语法格式进行验证
准备:
为静态的变量进行内存分配
静态常量在编译期间就初始化
解析:
将符号引用转为直接引用
将字节码的表现形式转为内存中的表现形式(内存地址)
初始化:
类的初始化,为类中的定义的静态变量进行赋值
3.初始化
为类中的定义的静态变量进行赋值
- 类什么时候会初始化?
在类中运行main方法
创建对象
使用类中的静态变量以及静态方法
反射Class.forNname("类的地址")
初始化子类的同时也会初始化其父类
注意:以下两种情况不会进行类初始化
先创建两个类
public class User {
static int a=10;
static final int b=20;
static{
System.out.println(a);
}
public class TestUser {
public static void main(String[] args) {
}
引用该类的静态常量
public class TestUser {
public static void main(String[] args) {
System.out.println(User.b);//调用类中的静态常量不会导致类的加载,有时会在常量在进行计算的情况下才会导致类的加载
}
构造某一个类的数组时
public class TestUser {
public static void main(String[] args) {
User[] users=new User[10];//构造某个类的数组时不会导致该类的初始化
}
6.类加载器
引导类加载器 :用c/c++语言进行开发,java底层的开发语言,负责加载java核心类库
扩展类加载器 :加载jdk下的 jre/lib/ext 子目录下加载类库
应用程序类加载器:加载程序中自己开发的类
ClassLoader classLoader=User.class.getClassLoader();
ClassLoader classLoader1=classLoader.getParent();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2 程序类加载器
System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@1b6d3586 扩展类加载器
ClassLoader classLoader2=String.class.getClassLoader();
System.out.println(classLoader2);//null 启动类加载器
双亲委派机制:
我们以String类为例,创建一个java.lang.String的一个类
public class String {
static{
System.out.println("自己创建的String类");
}
public static void main(String[] args) {
/*错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application*/
}
我们在类中添加了一个main方法,按道理启动应该是没有什么大问题的,但是当我们运行之后,idea给我们报了一个错,说是在String这个类中找不到main方法,那发生这样的原因是什么呢
原理:当一个类加载器收到类加载请求时,先会委托给父类加载器加载,如果父类加载器还有其父类,则继续向上委托,直到到根加载器(引导类加载器),如果还是找不到,则向下交给子类进行加载,一次类推,直到加载成功或者报错 ClassNotFoundException 异常。