java类的加载

1、类的加载概述

1.1 类加载

我们编写的".java"扩展名的源代码文件中存储着要执行的程序逻辑,这些文件需要经过java编译器编译成".class"文件,".class"文件中存放着编译后虚拟机指令的二进制信息。当需要用到某个类时,虚拟机将会加载它,并在内存中创建对应的class对象,这个过程称之为类的加载

一个类的生命周期从类被加载、连接和初始化开始;只有在虚拟机内存中,我们的java程序才可以使用它。整个过程如下图所示: 

 

2、类的加载、类的连接、类的初始化

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过这三个步骤来对类进行初始化。如果不出现意外情况,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或类初始化

2.1 类的加载

  • 就是指将class文件读入内存,并为之创建一个java.lang.Class对象。

类的加载是通过类的全限定类名(包名.类名)查找到该类的字节码文件,将.class文件的二进制数据读入到虚拟机内存中,并存放在运行时的方法区内;然后利用字节码文件创建一个Class对象,存放在堆区。

2.2 类的连接

  • 验证阶段:用于检验被加载的类是否有正确的内部结构(正确性),并和其他类协调一致
  • 准备阶段:负责为类的类变量(类的静态变量)分配内存,并设置默认初始化值
  • 解析阶段:将类的二进制数据中的符号引用替换为直接引用

其中,直接引用是直接指向目标的指针、偏移量等。

2.3 类的初始化

初始化阶段虚拟机规范规定了如下几种情况,如果类未初始化会对类进行初始化:

1)通过new关键字,创建类的实例

2)访问类的静态变量

3)访问类的静态方法

4)反射 Class.forName("")

5)当初始化一个类时,发现其父类还未初始化,则先进行父类的初始化

6)虚拟机启动时,定义了main方法的那个类先初始化

类加载的最后阶段,若该类具有父类,则先对父类进行初始化,执行静态变量赋值和静态代码块,成员变量也将被初始化。

  • 主要是对类变量和成员变量进行初始化

 

3、类加载器

类的加载是由类加载器完成的。类加载器可以分为两种:第一种是java虚拟机自带的类加载器,分别为根类加载器、扩展类加载器和系统类加载器;第二种是用户自定义的类加载器,是java.lang.ClassLoader的子类实例。

 3.1 虚拟机内置加载器

3.1.1 根类加载器(Bootstrap) -- 启动类加载器

根类加载器是最底层的类加载器,是虚拟机的一部分,它是由C++实现的,且没有父加载器,也没有继承java.lang.ClassLoader类。它主要负责加载由系统属性"sun.boot.class.path"指定的路径下的核心类库,即<JAVA_HOME>\jre\lib

 

3.1.2 扩展类加载器(Extension)

扩展类加载器是指由原SUN公司实现的类,由java语言编写,父加载器是根类加载器。

 

3.1.3 系统类加载器(System) 

应用类加载器:AppClassLoader (也叫做“系统类加载器”) -- 该加载器是程序中默认的类加载器。

3.1.4 小结

在程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,同时我们还可以自定义类加载器。注意,Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象;而且加载某个类的class文件时,java虚拟机采用的是双亲委派模式,即把加载类的请求交由父加载器处理,是一种任务委派模式。

3.2  类加载器的双亲委派机制

除了根类加载器外,其它的类加载器都需要有自己的父加载器。类的加载过程采用双亲委派机制,这种机制能够很好的保护java程序的安全。除了虚拟机自带的根类加载器之外,其余的类加载器都有唯一的父加载器。

比如,如果需要classLoader加载一个类时,该classLoader先委托自己的父加载器首先去加载这个类:若父加载器能够加载,则由父加载器加载;否则才由classLoader自己加载这个类。

即每个类加载器都很懒,加载类时都先让父加载器去尝试加载,一直到根类加载器,都加载不到时自己才去加载。真正加载类的加载器我们叫做启动加载器。

注意,双亲委派机制的父子关系并非面向对象程序设计中的继承关系,而是通过使用组合模式来复用父加载器代码,这种机制如下图所示:

使用双亲委派机制的好处:

 

 3.3 ClassLoader

所有的类加载器(除了根类加载器)都必须继承java.lang.ClassLoader。它是一个抽象类,主要方法如下:

3.3.1 loadClass

3.3.2 findClass

 在自定义类加载器时,一般需要覆盖这个方法,且ClassLoader中给出了一个默认的错误实现。

3.3.3 defineClass

 

3.4 URLClassLoader

 

 

3.5 自定义类加载器

我们如果需要自定义类加载器,只需要继承ClassLoader类,并覆盖掉findClass方法即可。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值