Java虚拟机之类加载

一,类文件结构

Class文件是一组以8字节为基础单位的二进制流。各个数据严格按照顺序紧凑地排列在Class文件中。

Class文件包含两种数据类型:无符号数和表

无符号数:u1,u2,u4,u8(分别代表1,2,4,8字节)

表:由多个无符号数或者其它表作为数据项构成的复合数据类型。所有表习惯性以“.info”结尾

class文件中的每个字节,长度,先后顺序都是被严格控制,不允许改变。

class文件结构:

魔数——class文件版本——常量池——访问标志——类索引,父类索引与接口索引集合——字段表集合——方法表集合——属性表集合(关于这部分可以直接通过javap反编译出来,笔者再此不作过多介绍)

二,类加载机制

类加载过程.png

类加载的生命周期:加载-验证-准备-解析-初始化-使用-卸载

为了支持java语言的动态绑定,除了加载-验证-准备-初始化-卸载 这5个阶段的先后次序是确定的,其余的都不是。

2.1 类加载过程

加载 :

  • 通过一个类的全限定名来获取定义此类的二进制字节流
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据
  • 在内存中生成一个代表此类的java.lang.Class对象,作为方法区这个类的访问入口。

验证:确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全

  • 文件格式验证:验证字节流是否符合class文件格式规范,并且能对当前虚拟机版本处理
  • 元数据验证:对字节码描述的信息进行语义分析,保证符合java语言规范的要求
  • 字节码验证:通过数据流和控制流进行分析,确定程序含义合法符合逻辑
  • 符号引用验证:对类自身以外的信息进行匹配性校验(常量池中的各种符号引用)

准备:为类变量(static修饰的变量)分配内存和设置初始值(数据类型的零值)。

如果变量还加有final修饰,则准备阶段就将其值初始化为指定的值。

解析:虚拟机将常量池内的符号引用替换为直接引用的过程。

  • 类或接口
  • 字段
  • 类方法
  • 接口方法
  • 方法类型
  • 方法句柄
  • 调用点限定符

初始化:初始化是类加载的最后一步,初始化是执行类构造器<clinit>()的过程。

进行初始化的条件:

  • 使用new 关键字实例化对象的时候,设置或读取一个类的静态字段(被final修饰除外,这个在编译期就已经放入常量池),调用一个类的静态方法

  • 使用反射的时候

  • 当初始化一个类时,父类还没有被初始化

  • 当虚拟机启动时,用户指定执行的主类,虚拟机会先初始化这个主类

  • 使用动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果ref_getStatic,ref_putStatic,ref_invokeStatic的方法句柄,如果这个类没有被初始化。

    需要注意的是有且只有满足这五种条件中的一种才能进行初始化。

    虚拟机规定,除了这五种场景之外所有的引用类都不会触发初始化,其它的引用都被称为被动引用。

    可以分析下几段代码

    package classLoadTest;
    
    /**
     * @author zhaokai008@ke.com
     * @date 2019-04-02 20:33
     */
    public class Super {
        public static int supT = 1;
        static {
            supT  =2;
            System.out.println("super init");
        }
        public static String value = "test";
    
        public static final String finalTest= "finalTest";
    }
    
    
    //*****
    package classLoadTest;
    
    /**
     * @author zhaokai008@ke.com
     * @date 2019-04-02 20:35
     */
    public class Sub extends Super {
    
        public static int Sub =supT;
    
        static {
            System.out.println("sub init ");
        }
    
    }
    
    //*****
    package classLoadTest;
    
    import org.junit.Test;
    
    /**
     * @author zhaokai008@ke.com
     * @date 2019-04-02 20:36
     */
    public class test {
    
    
    
    
        @Test
        public void testsub(){
            System.out.println(Sub.value);
        }
    
        @Test
        public void finalTest(){
            System.out.println(Super.finalTest);
        }
    
        @Test
        public void staticTest(){
            System.out.println(Sub.Sub);
        }
    }
    
    
    

当执行testSub()方法的时候:

super init
test

可见子类并没有被初始化。因为通过子类来调用父类的静态变量时,父类满足上诉第一条,父类被初始化,而子类不满足上述五条的任何一条,所以不会输出:sub init

当执行finalTest()方法时:

finalTest

并没有输出 super init 。这是因为 finale 修饰的字段在准备阶段就已经被加入到test类常量池里面去了,而super类不满足上诉五种条件中的一种,所以不会被初始化。

当执行staticTest 方法时:

super init
sub init
2

这里sub 类也被初始化了,因为调用了sub类的静态变量,符合1,而值时2,说明了父类的初始化会在子类之前完成,这里验证了下面的2

初始化注意的点:

  • Static{}静态语句中只能访问到定义在语句块之前的变量
  • <clinit>()方法与类的构造函数不同,不需要显示的调用父类构造器。虚拟机会保证父类在子类之前完成,所以父类的静态语句块要先与子类执行
  • <clinit>()对于类和接口不是必须的,没有静态语句块,没有对变量进行付值就不需要。
  • 接口不能使用静态语句块
  • 虚拟机会保证一个类的<clinit>()方法在多线程中被正确的加锁,同步。

2.2 类加载器

对于任何一个类都需要它的类加载器和这个类本身一同确定其在虚拟机中的唯一性。

从虚拟机角度来看只有两种类加载器:启动类加载器和其它。

从java开发者角度来说,有三种:启动类加载器,扩展类加载器,应用程序加载器

双亲委派模型 :

双亲委派模型.png

如果一个类加载器收到了类加载的请求,他首先会委派给父类加载器去完成,如果父类无法完成,则子类才会去尝试。

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

推荐阅读更多精彩内容