类加载
JVM进程被终止的情况:
- 运行完正常结束
- 执行System.exit()或Runtime.getRuntime().exit()
- 遇到未捕获异常或错误而结束
- 强制结束JVM进程
类使用/加载三步骤:装载、连接、初始化
类的加载:指的是将类的class文件读入内存,并为之创建一个java.lang.Class对象
类的连接:负责把类的二进制数据合并到JRE中。又分为3个阶段:
- 验证/校验:检查载入Class文件
- 准备:给类的静态变量分配存储空间并设置初始值
- 解析:非必须,将类的二进制数据中的符号引用替换成直接引用
类的初始化:对类的静态变量(声明变量时指定初始值)、静态代码块进行初始化工作。
记住一个过程:先默认值,比如int i就是0,然后按照先后顺序执行代码(含静态代码块)
类的初始化会处理静态变量以及执行静态代码块。
类初始化时机即出现如下任意一种情况都会触发类的初始化(想想单例的懒加载)
- 创建类的实例(含new、反射、反序列化)
- 调用类的静态方法
- 访问某个类或接口的类变量,或为该类变量赋值。
- 使用反射强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类。初始化子类,其所有父类都会被初始化、
- 运行的主类
- 被final修饰的类变量(已经确定其值),被调用时不初始化该类,如果其值不能确认static final String now = System.currentTimeMills() + “”;这种就会被初始化
- ClassLoader#loadClasss方法加载某类,也不会引起该类初始化
- Class#forName方法加载某类时,会强制初始化
类加载器
类加载器负责把.class文件加载到内存中,并生成对应的java.lang.Class对象。对于一个加载器,只要加载过并且内存中有,就不会再次加载。
对jvm同一个类:类全限定名+其类加载器,2个都一样才认为是同一个类。
分类
JVM启动时,就会形成3个类加载器:
- BootstrapClassLoader,根类加载器,非java语言。读jre的类,通过
URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
for(URL url : urLs){
System.out.println(url.toExternalForm());
}
- ExtensionClassLoader:扩展类加载器,java,是BootstrapClassLoader的子类。读jre/lib/ext下的类
- SystemClassLoader:系统类加载器也叫应用类加载器,读-classpath、java.class.path系统属性或CLASSPATH环境变量所指定jar或类,ClassLoader.getSystemClassLoader方法就是获取此类加载器的。
- 除了根加载器以外,所有的类加载器都是ClassLoader的子类
类加载器的3种机制
- 全盘负责:即一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他类,都由其负责载入,除非显示指定其他加载器。
- 父类委托:对应加载器,先让其父加载器加载,父无法处理,再由自己处理
- 缓存机制:保证所有加载过的Class都会被缓存,当程序需要使用某个class时,类加载器先从缓存中找,不存在,才去加载,存在直接使用,这也是为啥修改某个类后,需要重启jvm才能失效的原因。
查找一个类的位置