简单理解,就是把人写的东西变成机器读到东西;也叫编译?这是编译,编译不是加载;加载也不是初始化。
.java->.class->ClassLoader->init
我们编写的java文件都是保存着业务逻辑代码。java编译器将 .java 文件编译成扩展名为 .class 的文件。.class 文件中保存着java转换后,虚拟机将要执行的指令。当需要某个类的时候,java虚拟机会加载 .class 文件,并创建对应的class对象,将class文件加载到虚拟机的内存,这个过程被称为类的加载。
读取编译后的.class文件到虚拟机内存,这叫类的加载。
类的生命周期:加载,验证,准备,解析,初始化
加载
类加载过程的一个阶段,ClassLoader通过一个类的完全限定名查找此类字节码文件,并利用字节码文件创建一个class对象,在堆中。
用了类的完全限定名,这和反射有点像。所以创建类的方式到底层都只有反射而已,或者说都离不开类的全限定名。
验证
确保安全,是虚拟机可以读的信息。
此阶段主要确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机的自身安全。
准备
为类变量分配内存,并将其初始化为默认值(是默认值null和空,不是初始值)。还没有赋值!!
解析
把常量池中的符号引用转为直接引用。
初始化
这时候会有初始值了;如果该类具有父类就进行对父类进行初始化。
初始化做什么事?
使用new关键字实例化对象。执行其静态初始化器(静态代码块)和静态初始化成员变量。
不好理解的话就用我最擅长的方式来讲解
拿菜,洗菜,切菜分盘,分配配料,炒菜。
拿菜:加载,从一堆文件中吧“菜”加载到“桌上(堆内存)”。
洗菜:校验,洗掉农药确定不会对“身体(虚拟机)”造成危害。
切菜分盘:准备,给“切好的菜(类变量)”分配“盘中(内存)”,切开了就更占地方了,所有又要更多内存了。
分配配料:解析,查看做菜攻略,将上面写的配料找好(直接引用)。
炒菜:初始化,炒熟(执行静态代码),调味(变量赋初始值)。
类加载器
在java 虚拟机提供三种类加载器,引导类加载器,扩展类加载器,系统类加载器。
类加载器的任务,根据类的全限定名来读取此类的二进制字节流到 JVM 中,然后转换成一个与目标类对象的java.lang.Class 对象的实例
双亲委派
有事都推给爸爸做;除非爸爸做不了,不然自己不动手。
如果一个类加载器收到了类加载器的请求.它首先不会自己去尝试加载这个类.而是把这个请求委派给父加载器去完成.每个层次的类加载器都是如此.因此所有的加载请求最终都会传送到Bootstrap类加载器(启动类加载器)中.只有父类加载反馈自己无法加载这个请求(它的搜索范围中没有找到所需的类)时.子加载器才会尝试自己去加载。
优点:通过这种层级关系可以避免类的重复加载,当父亲已经加载了该类的时候,就没有必要子类加载器(ClassLoader)再加载一次。
这个设定感觉是怕自己乱定义类加载器,导致出现奇怪的错误;自定义的类加载器就只能加载自己写的新类。
forName和loaderClass区别,反射和加载的区别?
反射出来的类是已经初始化的,加载就只是加载了而已。