类加载器

Posted hup666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了类加载器相关的知识,希望对你有一定的参考价值。

一  类加载器

 

 

二  解析和分配

1,解析阶段

我们知道,类的加载过程包含七个阶段:加载,验证,准备,解析,初始化,使用,卸载,七个阶段顺序开始,交叉进行。解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,是这七个阶段之一。

      调用目标在程序代码写好、编译器进行编译时就必须确定下来。这类方法的调用称为解析。

在Java语言中符合“编译期可知,运行期不可变”这个要求的方法,主要包括静态方法和私有方法两大类,前者与类型直接关联,后者在外部不可被访问,这两种方法各自的特点决定了它们都不可能通过继承或别的方式重写其他版本,因此它们都适合在类加载阶段进行解析。

 

2 静态分派

多见于方法的重载 --- 编译时多态

 技术图片

 

 

 

“Human”称为变量的静态类型(Static Type),或者叫做的外观类型(Apparent Type),后面的“Man”则称为变量的实际类型(Actual Type),静态类型和实际类型在程序中都可以发生一些变化,区别是静态类型的变化仅仅在使用时发生,变量本身的静态类型不会被改变,并且最终的静态类型是在编译期可知的;而实际类型变化的结果在运行期才可确定,编译器在编译程序的时候并不知道一个对象的实际类型是什么。

代码中定义了两个静态类型相同但实际类型不同的变量,但虚拟机(准确地说是编译器)在重载时是通过参数的静态类型而不是实际类型作为判定依据的。并且静态类型是编译期可知的,因此,在编译阶段,Javac编译器会根据参数的静态类型决定使用哪个重载版本,所以选择了sayHello(Human)作为调用目标。所有依赖静态类型来定位方法执行版本的分派动作称为静态分派。静态分派的典型应用是方法重载。静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机来执行的。

 

3 动态分派

 多见于方法的覆盖---运行时多态

        静态类型同样都是Human的两个变量man和woman在调用sayHello()方法时执行了不同的行为,并且变量man在两次调用中执行了不同的方法。导致这个现象的原因很明显,是这两个变量的实际类型不同。

当子类未重写父类方法,如果用子类调用某个父类方法,按我们的理解是不是如果在子类找不到方法,就向上找父类的,依次类推

道理很简单,但是动态分派是个非常频繁的动作,如果每次都这么向上查找的话,会严重影响虚拟机的执行性能。所以虚拟机针对这种情况会做出一些优化手段,最常用的”稳定优化“手段就是为类在方法区中建立一个虚方法表(Virtual Method Table,也称为vtable),使用虚方法表的索引来代替元数据查找以提高性能。

      虚方法表中存放着各个方法的实际入口地址。如果某个方法在子类中没有被重写,那子类的虚方法表里面的地址入口和父类相同方法的地址入口是一致的,都指向父类的实现入口。如果子类中重写了这个方法,子类方法表中的地址将会替换为指向子类实现版本的入口地址。

 

      下图中Son重写了来自Father的全部方法,因此Son的方法表没有指向Father类型数据的箭头。但是Son和Father都没有重写来自Object的方法,所以它们的方法表中所有从Object继承来的方法都指向了Object的数据类型。

技术图片



 

以上是关于类加载器的主要内容,如果未能解决你的问题,请参考以下文章

在 CI 模板加载器类中加载一个或多个视图

Java 类加载器

类加载器

深入理解Java虚拟机——类加载机制

类加载器

类加载器