类的加载,连接,初始化
系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类
JVM和类
当调用java命令运行某个java程序时,该命令会启动一个java虚拟机进程。
同一个JVM的所有线程、所有变量都处于同一个进程里,他们都是用JVM进程的内存区。
JVM被终止的情况:
1、程序运行到最后正常结束。
2、程序运行到System.exit( )或者Runtime.getRuntime( ).exit( )代码结束程序
3、程序执行过程中遇到未捕获的异常或者错误结束
4、程序所在的平台强制结束了JVM进程
JVM进程结束,该进程在内存中的状态将会丢失
类加载
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化三个步骤来对类进行初始化。
Class类
class是对类的一种描述在java中的一种对象体现
类的加载
类的加载由类加载器完成,类加载器由JVM提供,用来将 .class文件(可能是磁盘上,也可能是网络上)加载到内存中,并生成对应的class对象
开发者可以通过继承ClassLoader基类来创建自己的类加载
通过使用不同的类加载器,可以从不同来源加载类的二进制数据,通常有如下几种来源
1、从本地文件系统加载class文件
2、从JAR包加载class文件(数据库驱动类放在JAR文件中,JVM可以从JAR文件中直接加载该class文件)
3、通过网络加载class文件
4、把一个java文件动态编译,并执行加载
注意:1、final修饰的类变量,如果该类变量在编译时期就可以确定下来,那么这个类变量相当于“宏观量”,
java编译器会在编译时直接把这个类变量出现的地方替换成它的值,因此即使程序使用该静态变量,也不会导致该类被初始化
2、当使用ClassLoader类的loadClass方法来加载某个类时,该方法只是加载该类,并不会执行类的初始化,
使用Class.forName( )静态方法才会导致强制初始化该类
类加载机制
类加载器负责载入所有的类,系统为所有被载入内存中的类生成一个class实例
在Java中,一个类使用其全限定类名(包括包名和类名)作为唯一标识
在JVM中,一个类使用其全限定类名(包括包名和类名)和类加载器对象作为唯一标识
JVM启动时,会形成由三个类加载器组成的初始类加载器层次结构
Bootstrap ClassLoader根类加载器
Extension ClassLoader扩展类加载器
System ClassLoader系统类加载器
用户类加载器(自定义加载器通过继承ClassLoader类来实现)
Bootstrap ClassLoader称为根类加载器、引导类加载器、原始类加载器,负责加载Java的核心类。
JVM的类加载机制有如下三种情况
1、父类委托:尝试先让父类加载器加载,父类无法加载,再尝试自己的类路径下加载(双亲委派模型)
2、全盘负责:加载某个Class的时候,该Class所依赖的和引用的其他Class都由该类加载器载入
3、缓存机制:所有加载过的Class都会被缓存,当程序需要用到某个Class的时候,先在缓存区中搜索是否存在,
不存在就读取并转换成Class对象保存到缓存区中
类加载器过程
1、检测此Class是否载入过(即在缓存区中是否有Class),如果有则直接进入第8步,否则执行第2步
2、如果父类加载器不存在,则进入第4步执行,如果父类加载器存在,则执行第3步
3、请求使用父类加载器去载入目标类,如果成功载入,则执行第8步,否则执行第5步
4、查找根类加载器是否载入,如果成功载入就进入第8步执行,否则执行第7步
5、当前类加载器尝试寻找Class文件,如果找到执行第6步,如果找不到则执行第7步
6、从文件中载入Class,载入成功后执行第8步
7、抛出ClassNotFoundException异常
8、返回对应的java.lang.Class对象
注意:其中第5、6步允许重写ClassLoader的finalClass方法来实现自己的载入策略,甚至可以重写loadClass方法来实现自己的载入过程
类加载器在加载类信息放到方法区中后,会创建一个对应的Class类型的实例放到堆(Heap)中,作为开发者访问方法区类定义的入口和切入点。
在堆区也创建了所有加载成功的类所对应的类加载器,也可以被获取