类加载的过程主要分为三个部分:加载,链接,初始化 而链接又可以细分为三个小部分:验证,准备,解析 加载 简单来说,加载指的是把class字节码文件从各个来源通过类加载器装载入内存中。 这里有两个重点: 字节码来源。一般的加载来源包括从本地路径下编译生成的.class文件,从jar包中的.class文件,从远程网络,以及动态代理实时编译 类加载器。一般包括启动类加载器,扩展类加载器,应用类加载器,以及用户的自定义类加载器。 验证 主要是为了保证加载进来的字节流符合虚拟机规范,不会造成安全错误。 包括对于文件格式的验证,比如常量中是否有不被支持的常量?文件中是否有不规范的或者附加的其他信息? 对于元数据的验证,比如该类是否继承了被final修饰的类?类中的字段,方法是否与父类冲突?是否出现了不合理的重载? 对于字节码的验证,保证程序语义的合理性,比如要保证类型转换的合理性。 准备 主要是为类变量(注意,不是实例变量)分配内存,并且赋予初值。 特别需要注意,初值,不是代码中具体写的初始化的值,而是Java虚拟机根据不同变量类型的默认初始值。 比如8种基本类型的初值,默认为0;引用类型的初值则为null;常量的初值即为代码中设置的值,final static tmp = 456, 那么该阶段tmp的初值就是456 解析 将常量池内的符号引用替换为直接引用的过程。 两个重点: 符号引用。即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息。 直接引用。可以理解为一个内存地址,或者一个偏移量。比如类方法,类变量的直接引用是指向方法区的指针;而实例方法,实例变量的直接引用则是从实例的头指针开始算起到这个实例变量位置的偏移量 举个例子来说,现在调用方法hello(),这个方法的地址是1234567,那么hello就是符号引用,1234567就是直接引用。 在解析阶段,虚拟机会把所有的类名,方法名,字段名这些符号引用替换为具体的内存地址或偏移量,也就是直接引用。 初始化 这个阶段主要是对类变量初始化,是执行类构造器的过程。 换句话说,只对static修饰的变量或语句进行初始化。 如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。 如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。
如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!
加入交流群
请使用微信扫一扫!