1、字节码文件
操作系统是无法直接看懂java代码的,所以需要使用javac指令将java代码编译成字节码文件 class,字节码文件就是二进制文件,操作系统能够理解其含义。
2、类加载的过程
loading:将字节码文件读到内存,并将这些数据转换成方法区的运行时数据(常量池、静态变量、静态代码块等),在堆中生成一个class对象代表这个类,作为方法区 类数据的访问入口(提供了反射的基本条件)
1、加载使用了双亲委派,主要出于安全来考虑
双亲委派模型用于 classLoader加载字节码文件的过程
每个classLoader都会管理一个缓存,存储已经加载过的class
从逻辑上讲,类加载顺序是 自定义类加载器(cutomClassLoader)有没有加载过该类,然后找父加载器,顺序是app - Extension - Bootstrap,如果都没有加载过,那么又反方向查找,看谁能加载就加载。
每个类加载器负责的范围都不一样,最顶级的是Bootstrap,负责加载 lib/rt.jar 等核心类库,由C++实现,基本上就是和操作系统打交道的方法了,native 方法,类加载器的职责描述在 Launcher 类里描述。
用源码上讲
当前类加载器执行 loadClass ->findLoadedClass -> parent.loadClass -> findClass
源码和模型如下图
tips:父加载器和当前的加载器并不是继承关系,这个parent的关系是指定的。
2、自定义类加载器
继承 classLoader ,并重写 findClass方法就可以
3、LazyLoading
说是懒加载,其实应该是懒初始化,jvm并没有规定什么时候加载某个类,但是严格规定了什么什么进行初始化,下述五种情况必须初始化
–new getstatic putstatic invokestatic指令,访问final变量除外(final变量在初始化之前就会在内存里开辟空间,可以直接访问)
–初始化子类的时候,父类首先初始化
–虚拟机启动时,被执行的主类必须初始化
–动态语言支持java.lang.invoke.MethodHandle解析的结果为REF_getstatic REF_putstatic REF_invokestatic的方法句柄时,该类必须初始化
public static void main(String[] args) throws Exception { P p = null; System.out.println(P.i);//此时没有new对象所以没有完成初始化过程,静态代码块也不会加载 } public static class P { final static int i = 8; static int j = 9; static { System.out.println("P"); } } public static class X extends P { static { System.out.println("X"); } }
Linking
Initializing
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。