类加载机制

类加载机制

类加载机制是指 .class文件加载到JVM,并形成Class对象的机制。

类加载机制可以在运行时动态的加载外部的类、远程网络下载过来 class 文件等。除了动态的优点wai外,还可以通过JVM的类加载机制来达到类隔离的效果。

JVM将类加载划分为三个步骤:

  • 装载
  • 链接
  • 初始化

装载和链接完成后就将二进制的字节码转换为 Class 对象;而初始化过程并不是加载类时必须触发的(为什么呢),但是最迟必须在初次主动使用对象前执行。

类加载过程
类加载过程

装载

装载过程负责找到二进制字节码并加载至JVM中,JVM通过类的全限定名类加载器完成类的加载,同样,也采用全限定名类加载器来标识一个被加载了的类:类的全限定名 + ClassLoader实例ID

类名的命名方式如下:

  • 对于接口或非数组型的类,其名称即为类名,此种类型的类由所在的ClassLoader负责加载;
  • 对于数组型的类,其名称为“[”+(基本类型|L)+引用类型类名;)
byte[] bytes = new byte[512];
System.out.println(bytes.getClass().getName());

Object[] objects = new Object[10];
System.out.println(objects.getClass().getName());

String[] strings = new String[10];
System.out.println(strings.getClass().getName());
# Output ---
[B
[Ljava.lang.Object;
[Ljava.lang.String;

链接

一:校验 链接过程负责对二进制字节码的格式进行校验、初始化装载类中的静态变量及解析类中调用的接口和类。

校验过程中如果碰到要引用到其他的接口和类,也会进行加载;如果加载过程失败,则会抛出NoClassDefFoundError。

二:准备 在完成了校验后,JVM初始化类中的静态变量,并将其值赋为默认值。

三:解析 最后对类中的所有属性、方法进行验证,以确保其要调用的属性、方法存在,以及具备相应的权限(例如public、private域权限等)。如果这个阶段失败,可能会造成NoSuchMethodEr-ror、NoSuchFieldError等错误信息。

初始化

初始化过程即执行类中的静态初始化代码、构造器代码及静态属性的初始化。

以下四种情况下初始化过程会被触发执行:

  1. 调用了new;
  2. 反射调用了类中的方法;
  3. 子类调用了初始化;
  4. JVM启动过程中指定的初始化类。

在执行初始化过程之前,首先必须完成链接过程中的校验和准备阶段,解析阶段则不强制。

JVM的类加载通过ClassLoader及其子类来完成:

  • Bootstrap ClassLoader 在代码中没有办法拿到这个对象,Sun JDK启动时会初始化此ClassLoader,并由ClassLoader加载$JAVA_HOME/jre/lib/rt.jar里所有class文件;
  • Extension ClassLoader JVM用此ClassLoader来加载扩展功能的一些jar包 $JAVA_HOME/jre/lib/ext/*.jar;
  • System ClassLoader(AppClassLoader) JVM用此ClassLoader来加载启动参数中指定的Classpath中的jar包及目录,在Sun JDK中ClassLoader对应的类名为AppClassLoader;
  • UserDefined ClassLoader 继承Class-Loader抽象类自行实现的ClassLoader,基于自定义的ClassLoader可用于加载非Classpath中(例如从网络上下载的jar或二进制)的jar及目录、还可以在加载之前对class文件做一些动作(例如解密等)。
public class ClassTest {

    @Test
    public void testClassLoader() {
        System.out.println(ClassTest.class.getClassLoader());
        System.out.println(ClassTest.class.getClassLoader().getParent());
        System.out.println(ClassTest.class.getClassLoader().getParent().getParent());
    }
}

# Output ---
sun.misc.Launcher$AppClassLoader@3836b1bb
sun.misc.Launcher$ExtClassLoader@ece88d2
null

ClassLoader继承关系
ClassLoader继承关系

JVM的ClassLoader采用的是树形结构,除BootstrapClass-Loader外,其他的ClassLoader都会有parent ClassLoader,UserDefined ClassLoader默认的parent ClassLoader为System ClassLoader。加载类时通常按照树形结构的原则来进行,也就是说,首先应从 UserDefined ClassLoader中尝试进行加载,当par-ent中无法加载时,应再尝试从System ClassLoader中进行加载,System ClassLoader同样遵循此原则,在找不到的情况下会自动从其parent ClassLoader中进行加载。

JVM是采用类名+Classloader的实例来作为Class加载的判断的,因此加载时不采用上面的顺序也是可以的,例如加载时不去parent ClassLoader中寻找,而只在当前的ClassLoader中寻找,会造成树上多个不同的ClassLoader中都加载了某Class,并且这些Class的实例对象都不相同。

当Java开发人员调用Class.forName来获取一个对应名称的Class对象时,JVM会从方法栈上寻找第一个ClassLoader,通常也就是执行Class.forName所在类的ClassLoader,并使用此ClassLoader来加载此名称的类。


ClassNotFoundException 这是最常见的异常,产生这个异常的原因为在当前的ClassLoader中加载类时未找到类文件,对位于System ClassLoader的类很容易判断,只要加载的类不在Classpath中。而对位于UserDefined ClassLoader的类则麻烦些,要具体查看这个ClassLoader加载类的过程,才能判断此ClassLoader要从什么位置加载到此类。例如直接在代码中执行Class.forName(“com.blue-davy.A”),而当前类的classloader下根本就没有该类所在的jar或没有该class文件,就会抛出ClassNotFoundException。

NoClassDefFoundError 该异常较之ClassNotFoundException更难处理一些,造成此异常的主要原因是加载的类中引用到的另外的类不存在,如下:要加载A,而A中调用了B,B不存在或当前ClassLoader没法加载B,就会抛出这个异常。当采用Class.forName加载A时,虽能找到A.class,但此时B.class不存在,则会抛出NoClassDefFoundError。

public class A {  
private B b=new B();
    
}

ClassCastException 这个异常比较难查的是两个A对象由不同的ClassLoader加载的情况,这时如果将其中某个A对象造型成另外一个A对象,也会报出ClassCastException。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容