1.类加载过程:
首先要加载某个类一定是出于某种目的,比如要运行java程序,那么久必须加载主类才能运行其中的方法,所以一般在这些情况下,如果类没有被加载,就会自动被加载:
1.使用new创建对象时
2.使用某个类的静态成员的时候,当然final这种类型的静态字段是有可能在编译的时候被放到当前类的常量池中
3.使用反射对类信息进行获取的时候
4.加载一个类的子类的时候
5.加载接口的类实现,且接口带有default方法默认实现的时候。
2.类的生命周期
首先类的生命周期一共有7个阶段,而首当其冲的就是加载,加载阶段需要获取此类的二进制数据流,比如我们要从硬盘中读取一个class文件,那么就可以通过文件输入流来获取类文件的byte[],也可以是其他各种途径获取类文件的输入流,甚至网络传输并加载一个类也不是不可以。然后交给类加载器进行加载(类加载器可以是JDK内置的,也可以是开发者自己撸的,后面会详细介绍)类的所有信息会被加载到方法区中,并且在堆内存中会生成一个代表当前类的Class类对象(那么思考一下,同一个Class文件加载的类,是唯一存在的吗?),我们可以通过此对象以及反射机制来访问这个类的各种信息。
数组类型本身不会通过类加载器进行加载的,不过你既然要往里面丢对象进去,那最终依然是要加载类的。
接下来就是准备阶段了,这个阶段会为类变量分配内存,并为一些字段设定初始值,注意是系统规定的初始值,不是我们手动指定的初始值。
再往下就是解析阶段,此阶段是将常量池内的符号引用替换为直接引用的过程,也就是说,到这个时候,所有引用变量的指向都是已经切切实实地指向了内存中的对象了。
到这里,链接过程就结束了,也就是说这个时候类基本上已经完成大部分内容的初始化了。
最后就是真正的初始化阶段了,从这里开始,类中的Java代码部分,才会开始执行,还记得我们之前介绍的<clinit>方法吗,它就是在这个时候执行的,比如我们的类中存在一个静态成员变量,并且赋值为10,或是存在一个静态代码块,那么就会自动生成一个<clinit>方法来进行赋值操作,但是这个方法是自动生成的。
全部完成之后,我们的类就算是加载完成了。
3.类加载器
Java提供了类加载器,以便我们自己可以更好地控制类加载,我们可以自定义类加载器,也可以使用官方自带的类加载器去加载类。对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性。
也就是说,一个类可以由不同的类加载器加载,并且,不同的类加载器加载的出来的类,即使来自同一个Class文件,也是不同的,只有两个类来自同一个Class文件并且是由同一个类加载器加载的,才能判断为是同一个。默认情况下,所有的类都是由JDK自带的类加载器进行加载。