深入理解JVM(学习过程) (4)

接口本身的成员变量 都是 public static final 的

/** 当一个接口在初始化时,并不要求其父接口都完成了初始化。 只有在真正使用到父接口的时候(如 引用接口中所定义的常量时),才会初始化。 */ public class MyTest5{ public static void main(String[] args){ System.out.println(myParent5.b); } } interface MyParent5{ public static int a = 5; } interface MyChild5 extends MyParent5{ public static int b = 6; } /** class MyChild5 implements MyParent5{ public static int b = 6; } **/ 类的初始化顺序 /* 这个例子很好的阐述了类初始化的顺序问题。 */ public class MyTest6{ public static void main(String[] args) { Singleton singleton = Singleton.getInstance(); System.out.println("counter1:"+Singleton.counter1); System.out.println("counter2:"+Singleton.counter2); } } class Singleton{ public static int counter1 = 1; private static Singleton singleton= new Singleton(); private Singleton(){ counter1++; counter2++; // 准备阶段的重要意义 System.out.println(counter1); System.out.println(counter2); } public static int counter2 = 0; public static Singleton getInstance(){ return singleton; } } > Task :MyTest6.main() 2 1 counter1:2 counter2:0 类加载的加载顺序

image-20200208221610181

image-20200208221655905

类加载器 类加载的概念回顾

类的加载

类的加载的最终产品是位于内存中的Class对象

Class对象封装了类在方法去内的数据结构并且向Java程序员提供了访问方法区内的数据结构的接口。

有两种类型的类加载器

Java虚拟机自带的加载器

根类加载器(BootStrap)(BootClassLoader)

扩展类加载器(Extension)(ExtClassLoader)

系统(应用)类加载器(System)(AppClassLoader)

用户自定义的类加载器

Java.long.ClassLoader的子类

用户可以定制类的加载方式

类加载器并不需要等到某个类被“首次使用”时再加载它。

jvm规范允许类加载器在预料某个类将要被使用时就预先加载他,如果在预先加载的过程中遇到了.class文件缺失或者存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)

如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误

image-20200212204737909

image-20200212171808157

image-20200208223421181

image-20200208223434835

image-20200208223505045

image-20200208223542725

依次执行初始化语句:按照CLass类文件中的顺序加载静态方法和静态代码块。

image-20200208223642407

image-20200208223705030

image-20200208223738483

重点介绍一下上图的概念。举例说明。

在初始化一个接口时,并不会先初始化它的父接口。

// 当一个类初始化时,它实现的接口是不会被初始化的。 public class MyTest5{ public static void main(String[] args){ System.out.println(MyChild5.b); } } interface MyParent5{ public static Thread thread = new Thread(){ // 每次被实例化的时候都会执行下方的代码块。 如果是 static{} 的时候,只会被加载一次。 { System.out.println("myParent5 invoked"); } } } class MyChild5 implements MyParent5{ public static int b = 6; } // 在初始化一个接口时,并不会先初始化它的父接口 public class MyTest5{ public static void main(String[] args){ System.out.println(MyParent5_1.thread); } } interface MyParent5{ public static Thread thread = new Thread(){ { System.out.println("myParent5 invoked"); } } } interface MyParent5_1 extends MyGrandpa5_1{ public static Thread thread = new Thread(){ { System.out.println("myParent5 invoked"); } } }

image-20200208223917870

image-20200208223931946

调用CLassLoader类的loadCLass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。

类加载器深度剖析

image-20200208223947354

image-20200208224052752

image-20200208224219186

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfdfy.html