面试官:java类的加载过程

Java 类加载机制

类从被加载到JVM中开始,到卸载为止,整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。
其中类加载过程包括加载、验证、准备、解析和初始化五个阶段。

类的加载过程.png

类的加载过程

加载

1、通过类加载器,加载.class文件到内存中。
2、将读取到.classs数据存储到运行时内存区的方法区。
3、然后将其转换为一个与目标类型对应的java.lang.Class对象实例。这个Class对象在日后就会作为方法区中该类的各种数据的访问入口。

链接

验证

确保被加载的类(.class文件的字节流),是否按照java虚拟的规范。不会造成安全问题
1、文件格式验证:
第一阶段要验证字节流是否符合 Class文件格式的规范, 井且能被当前版本的虚拟机处理。这一阶段可能包括下面这些验证点:

  • 是否以魔数 0xCAFEBABE开头
  • 主、次版本号是否在当前虚拟机处理范围之内 。
  • 常量池的常量中是否有不被支持的常量类型(检査常量tag 标志)。
  • 指向常量的各种索引值中是否有指向不存在的常量或不符合装型的常量 。
  • CONSTANT_Utf8_info型的常量中是否有不符合 UTF8编码的数据
  • Class 文件中各个部分及文件本身是否有被删除的或附加的其他信息
    实际上第一阶段的验证点还远不止这些, 这是其中的一部分。只有通过了这个阶段的验证之后, 字节流才会进入内存的方法区中进行存储, 所以后面的三个验证阶段全部是基于方法区的存储结构进行的,不会再直接操作字节流。

2、元数据验证
第二阶段是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求,这个阶段可能包括的验证点如下:

  • 这个类是否有父类(除了java.lang.object之外,所有的类都应当有父类)
  • 这个类的父类是否继承了不允许被继承的类(被finaI修饰的类)
  • 如果这个类不是抽象类, 是否实現了其父类或接口之中要求实现的所有方法
    类中的字段、 方法是否与父类产生了矛盾(例如覆盖了父类的final字段, 或者出現不符合规则的方法重载, 例如方法参数都一致, 但返回值类型却不同等)
    第二阶段的验证点同样远不止这些,这一阶段的主要目的是对类的元数据信息进行语义检验, 保证不存在不符合 Java语言规范的元数据信息。

3、字节码验证
第三阶段是整个验证过程中最复杂的一个阶段, 主要目的是通过数据流和控制流的分析,确定语义是合法的。符号逻辑的。在第二阶段对元数据信息中的数据类型做完校验后,这阶段将对类的方法体进行校验分析,保证被校验类的方法在运行时不会做出危害虚拟机安全的行为,例如:

  • 保证任意时刻操作数栈的数据装型与指令代码序列都能配合工作, 例如不会出现类似这样的情况:在操作栈中放置了一个 int类型的数据, 使用时却按long类型来加载入本地变量表中。
  • 保证跳转指令不会跳转到方法体以外的字节码指令上
  • 保证方法体中的类型转换是有效的, 例如可以把一个子类对象赋值给父类数据装型,这是安全的,但是把父类对象意赋值给子类数据类型,甚至把对象赋值给与它毫无继承关系、 完全不相干的一个数据类型, 则是危险和不合法的。
    即使一个方法体通过了字节码验证, 也不能说明其一定就是安全的。

4、符号引用验证
最后一个阶段的校验发生在虚拟机将符号引用转化为直接引用的时候 , 这个转化动作将在连接的第三个阶段——解析阶段中发生。符号引用验证可以看做是对类自身以外(常量池中的各种符号引用) 的信息进行匹配性的校验, 通常需要校验以下内容:

符号引用中通过字将串描述的全限定名是否能找到对应的类
在指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段 。
符号引用中的类、字段和方法的访问性(privateprotectedpublicdefault)是否可被当前类访问
符号引用验证的目的是确保解析动作能正常执行, 如果无法通过符号引用验证, 将会抛出一个java.lang.IncompatibleClassChangError异常的子类, 如 java.lang.IllegalAccessErrorjava.lang.NoSuchFieldErrorjava.lang.NoSuchMethodError等。

准备

主要是为类变量(注意,不是实例变量)分配内存,并且赋予初值,此时的赋值是Java虚拟机根据不同变量类型的默认初始值:
8种基本类型的初值,默认为0;引用类型的初值则为null;常量的初值即为代码中设置的值
1、final static temp = 100,此时temp就是赋值 100
2、String temp = “123456”,此时temp值就是null
3、int temp = 100,此时temp值就是0

解析

将类的二进制数据中的符号引用替换成直接引用(符号引用是用一组符号描述所引用的目标;直接引用是指向目标的指针)

可以认为是一些静态绑定的会被解析,动态绑定则只会在运行时进行解析;静态绑定包括一些final方法(不可以重写),static方法(只会属于当前类),构造器(不会被重写)

在解析阶段,虚拟机会把所有的类名,方法名,字段名这些符号引用替换为具体的内存地址或偏移量,也就是直接引用。

初始化

初始化,则是为标记为常量值的字段赋值的过程。
换句话说,只对static修饰的变量或语句块进行初始化。
如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。
如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。

涉及问题

一个类的构造器,代码块,静态代码块,成员变量的 的执行顺序。

//父类
public class ParentClass {
    private int p1 = getValue() ;
    private static int p2 = getValue2();
    public ParentClass(){
        System.out.println("我是父构造器");
    }
    static {
        System.out.println("我是父静态代码块1");
    }
    static {
        System.out.println("我是父静态代码块2");
    }
    {
        System.out.println("我是父代码块1");
    }
    {
        System.out.println("我是父代码块2");
    }

    private int getValue(){
        System.out.println("我是父成员变量p1");
        return 1;
    }

    private static int getValue2(){
        System.out.println("我是父静态成员变量p2");
        return 1;
    }

}
//子类
public class ChildClass extends ParentClass{
    private int c1 = getValue() ;
    private static int c2 = getValue2();

    public ChildClass(){
        System.out.println("我是子构造器");
    }
    static {
        System.out.println("我是子静态代码块1");
    }
    static {
        System.out.println("我是子静态代码块2");
    }
    {
        System.out.println("我是子代码块1");
    }
    {
        System.out.println("我是子代码块2");
    }

    private int getValue(){
        System.out.println("我是子成员变量c1");
        return 1;
    }

    private static int getValue2(){
        System.out.println("我是子静态成员变量c2");
        return 1;
    }

    public static void main(String[] args) {
        ChildClass childClass = new ChildClass();
    }
}

执行结果:
我是父静态成员变量p2
我是父静态代码块1
我是父静态代码块2
我是子静态成员变量c2
我是子静态代码块1
我是子静态代码块2
我是父成员变量p1
我是父代码块1
我是父代码块2
我是父构造器
我是子成员变量c1
我是子代码块1
我是子代码块2
我是子构造器

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