类的加载

类的生命周期

在这里插入图片描述
上述的7个阶段中,只有加载、校验、准备、初始化、卸载,这五个阶段的顺序是固定的。

类的加载过程

在这里插入图片描述

加载

1、将字节码文件转换成二进制字节流
2、字节流以某种数据结构存放在方法区
3、创建java.lang.Class的一个实例对象,存放在方法区。

校验

校验calss文件的字节流中包含的信息是否符合虚拟机规范,防止对虚拟机自身造成危害。
校验一共有以下4个阶段。

  • 文件格式验证
  • 元数据验证
  • 字节码验证
  • 符号引用验证

准备

把类变量存放在方法区中,并赋予初值。

public static int a=3;

此时a的初值就是0.

public static final int a=3;

此时a的初值是3.

注意区分以上两种情况。

解析

将符号引用转化成直接引用。
解析阶段一般发生在初始化完成之后。

初始化

执行类构造器<clinit>的过程。
类构造器是编译器自动生成的,而不需要用户自己定义。
编译器收集类变量的赋值动作和静态代码块,并将它们合并在一起,组成了类构造器。

public class Student {
    public static int a=3;
    static{
        a=4;
        b=10;
    }
    public static int b=4;
}

Student的类构造器如下所示:

  static <clinit>()V
   L0
    LINENUMBER 4 L0
    ICONST_3
    PUTSTATIC JVM/Student.a : I
   L1
    LINENUMBER 6 L1
    ICONST_4
    PUTSTATIC JVM/Student.a : I
   L2
    LINENUMBER 7 L2
    BIPUSH 10
    PUTSTATIC JVM/Student.b : I
   L3
    LINENUMBER 9 L3
    ICONST_4
    PUTSTATIC JVM/Student.b : I
    RETURN
    MAXSTACK = 1
    MAXLOCALS = 0
}

可以发现编译器的收集顺序是自上而下的,故最终Student.a的值为4,Student.b的值为4.

虚拟机会保证类构造器在多线程环境下是同步加锁的。

public class ThreadTest {
    public static void main(String[] args) {
        new Thread(()->{
            System.out.println(A.a);
        }).start();
        new Thread(()->{
            System.out.println(A.a);
        }).start();

    }

    static class A{
        public static int a=9;
        static {
            System.out.println("a...");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

通过上述代码可以发现,有两个线程,当其中一个线程,执行类构造器方法时,另一个线程一直在等待,直到方法执行结束,才输出了静态变量的值。

类加载器

这些类加载器之间并不是继承关系,而是组合(包含)关系
在这里插入图片描述

类加载器其实可以分为两类:引导类加载器和自定义加载器。
自定义加载器是指继承重写了ClassLoader抽象类的类加载器。扩展类加载器和系统类加载器都是自定义加载器。

双亲委派机制

java的类加载机制是一种按需加载的机制,只有当你真正要用到它的时候才会进行加载。

步骤:
1、一个类加载器收到类加载的请求,会把请求告诉它的父级类加载器。
2、父级类加载器也告诉它的父级类加载器,就这样不断递归,直至找到最顶级的引导类加载器。
3、若是父级类加载器可以加载该类,那么成功返回,若是不能加载,那么再反向委派给它的子级类加载器。

使用双亲委派机制的优势:
1、避免类的重复加载
2、保护程序安全,避免核心API被修改

java.lang.String

package java.lang;

public class String {
    public static void main(String[] args) {
        String str = "hello";
        System.out.println(str);
    }

}

在这里插入图片描述
会出现以上的错误,就是因为双亲委派机制的功劳。
让类加载器加载java.lang.String这个类,引导类发现这个类以java开头,所以它可以加载,于是把java自己的String类加载进来,可是这个类是没有main方法的,于是就出现了这个错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值