类加载机制

来源:互联网 发布:java图形界面开发教程 编辑:程序博客网 时间:2024/05/16 14:48

1、虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制;

2、与那些在编译器需要进行连接工作的语言不同,在java语言里,类型的加载、连接和初始化过程都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会为java应用程序提供高度的灵活性,java里天生可以动态扩展的语言特性就是依赖运行期动态加载和动态连接这个特点实现的。

3、生命周期:加载、验证、准备、解析、初始化、使用、卸载;

4、加载,java虚拟机规范中没有进行强制约束,这点由虚拟机具体实现自由把握;

5、初始化,严格规定了有且只有一下情况必须立即执行(加载验证等操作在此之前开始):代码场景(new,调用静态方法等),对类反射调用时,初始化时先触发父类初始化,main方法所在类等


6、加载只是类加载过程的一个阶段,加载过程需要完成:1、通过一个类的全限定名来获取定义此类的二进制字节流;2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;3、在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据的访问入口;

7、验证是连接阶段的第一步,这个阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求;

8、准备阶段是正式为类变量分配内存并设置类变量初始值得阶段,这些变量所使用的内存都将在方法区中进行分配。注意,仅分配类变量(被static修饰过的变量),实例变量将在对象实例化的时候随对象一起分配在java堆中;public static int value=123准备阶段过后初始值是0,而不是123,因为这时候尚未执行任何java方法;

9、解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程;

10、初始化阶段是类加载过程的最后一步,前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全有虚拟机主导和控制。到了初始化阶段才真正开始执行类中定义的java程序代码(或者说是字节码);


11、类加载过程中“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到虚拟机外部去实现,以便让应用程序自己决定入伙去获取所需要的类,实现这个动作的代码模块称为“类加载器”。

12、双亲委派:一个类加载器收到了类加载的请求,先把这个请求委派给父类加载器去完成,每个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有父加载器反馈自己无法完成这个加载请求(它的搜索范围没有找到所需的类),子类加载器才会尝试自己去加载;

13、使用双亲委派模型来组织类加载器之间的关系,有一个显而易见的好处就是java类随它的类加载器一起具备了一种带有优先级的层次关系。例如加载基础类,Object类等

14、破坏双亲委派模型:双亲委派模型并不是一个强制性的约束模型,而是java设计者推荐给开发者的类加载器实现方式。

15、例如jndi已经是java的标准服务,它的代码有启动类加载器加载(在rt.jar包中),但jndi的目的就是对资源进行集中管理和查找,需要调用有独立厂商实现并部署在应用程序的classpath下的jndi实现的代码,但启动器不可能“认识”这些代码,,,,为解决这个问题,java设计者引入了线程上下文加载器,这个类加载器可以通过Thread类的setContextClassLoader方法进行设置,如果创建线程时还未设置,会从父线程继承,如果在应用程序的全局范围内都没有设置过的话,那默认就是应用程序类加载器。有了这个类加载器,jndi服务就可以只用这个线程上下文类加载器去加载所需要的spi实现代码,也就是父类加载器请求子类加载器去完成类加载动作,打通了双亲委派模型的层次结构来逆向使用类加载器。java中所有涉及spi的加载动作基本都采用这种方式,例如jndi,jdbc等。


参考《深入理解java虚拟机》

原创粉丝点击