Java 类加载

1. 类加载流程

 

 

 

2. 加载

类加载过程的第⼀步,主要完成下⾯3件事情:

(1)通过全类名获取定义此类的⼆进制字节流

(2)将字节流所代表的静态存储结构转换为方法区的运行时数据结构(本质是C++的instanceKlass作为元数据来描述Java类)

(3)在内存中⽣成⼀个代表该类的 Class 对象(在堆中,和方法区里的java_mirror对应),作为⽅法区这些数据的访问⼊⼝

 

3. 验证

验证类是否符合 JVM规范,安全性检查

 

4. 准备

为static变量分配空间,设置默认值

 

5. 解析

将常量池中的符号引用解析为直接引用

public class Load2 {
    public static void main(String[] args) throws ClassNotFoundException, IOException {
    ClassLoader classloader = Load2.class.getClassLoader();
    // loadClass 方法不会导致类C的解析和初始化,由于懒加载,类D还没被用到,这样查看类C加载情况里类D只是一个符号
    Class<?> c = classloader.loadClass("cn.itcast.jvm.t3.load.C");
    // new C(); 会加载且解析且初始化,这样类C的加载情况里D的内存地址都有了
    System.in.read();
  }
} 
class C {   D d
= new D(); }
class D { }

 

6. 初始化

(1)初始化即调用<cinit>方法,虚拟机会保证该方法执行的线程安全

补充:<cinit>方法是在类加载过程中执行的,而<init>是在对象实例化执行的

<cinit>:父类静态变量初始化 > 父类静态代码块 > 子类静态变量初始化 > 子类静态代码块

<init>:父类变量初始化 > 父类构造代码块 > 父类构造函数 > 子类变量初始化 > 子类构造代码块 > 子类构造函数

(2)初始化是“懒惰的” (类开始加载的时机没有明确规定,但是初始化时机规定了)

比如子类访问父类静态变量只有父类初始化,访问final常量(基本类型和字符串)不会初始化,loadClass不会初始化,创建类的数组不会初始化等

 应用:懒加载的单例模式

class Singleton{
    //volatile关键字禁止指令重排
    private volatile static Singleton instance;
    private Singleton(){}
    public Singleton getInstance(){
        if(instance==null){
            //对.class加锁,获得的是所有类对象的锁
            synchronized (Singleton.class){
                //双重检查,防止多个线程同时进入第一层检查(因单例模式只允许存在一个对象,故在创建对象之前无引用指向对象,所有线程均可进入第一层检查)
                //当某一线程获得锁创建一个Singleton对象时,即已有引用指向对象,singleton不为空,从而保证只会创建一个对象
                //假设没有第二层检查,那么第一个线程创建完对象释放锁后,后面进入对象也会创建对象,会产生多个对象
                if(instance==null){
                    //singleton=new Singleton语句为非原子性,实际上会执行以下内容:
                    //(1)在堆上开辟空间;(2)属性初始化;(3)引用指向对象
                    //volatile关键字可保证singleton=new Singleton()语句执行顺序为123,引用指向对象时一定有对象了
                }
            }
        }
        return instance;
    }
}

 

7. 类加载器

(1)层级关系

 (2)双亲委派

系统中的 ClassLoader 在协同工作的时候会默认使用双亲委派模型 ;

即类加载时,首先会委派上级的类加载器的loadClass()方法,因此所有类加载器都会传到顶层启动类加载器,当父类加载器无法处理时,才有自己处理。

(3)判断两个类完全相同

包名,类名,类加载器均相同

 

8. javap工具分析类结构

javap -v HelloWorld.class

 

9. HSDB工具

HSDB是一个很强大的JVM运行时状态分析工具,根据线程id或name,可以查找类加载情况,内存地址,常量池内容等

java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB

 

10. 语法糖

所谓的语法糖 ,其实就是指 java 编译器把 *.java 源码编译为 *.class 字节码的过程中,自动生成和转换的一些代码,主要是为了减轻程序员的负担,算是 java 编译器给我们的一个额外福利(给糖吃嘛)

(1)默认构造器

(2)自动拆装箱JDK5

(3)泛型擦除:java 在编译泛型代码后会执行泛型擦除的动作,即泛型信息在编译为字节码之后就丢失了,实际的类型都当做了 Object 类型来处理(反射可以获得这些信息)

(4)可变参数:转换为数组

(5)foreach:转换为普通for循环

 

posted @ 2021-03-08 17:10  Kinghao0319  阅读(68)  评论(0编辑  收藏  举报