类加载子系统

类加载子系统

概述
在这里插入图片描述
完整图如下
在这里插入图片描述如果自己想手写一个java虚拟机的话,主要考虑拿些结构呢?

  • 类加载器
  • 执行引擎

类加载子系统的作用

类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。
ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定。
加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串常量和数字常量。
在这里插入图片描述

  • class file存在于本地硬盘上,可以理解为设计师画在纸上的模板,而最终这个模板在执行的时候是要加载到JVM当中来根据这个文件实例出n个一模一样的实例
  • class file加载到jvm中,被称为DNA元数据模板,放在方法区。
  • 在.class文件->JVM->最终成为元数据模板,此过程需要一个运输工具(类加载器Class Loader),扮演一个快递员的角色。
    在这里插入图片描述## 类加载过程
    例如下面的一段简单的代码
public class HelloLoader {
    public static void main(String[] args) {
        System.out.println("我已经被加载了");
    }
}

它的加载过程是怎么样的呢?
在这里插入图片描述
完整的流程图如下所示:
在这里插入图片描述## 加载阶段

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

加载Class文件的方式

  • 从本地系统直接加载
  • 通过网络获取,典型场景:web Applet
  • 从zip压缩包中读取,成为日后jar,war格式的基础
  • 运行时计算生成,使用最多的是:动态代理技术
  • 由其他文件生成,典型场景:JSP应用从专有数据库中提取.class文件,比较少见
  • 从加密文件获取,典型的防class文件被反编译的保护措施

链接阶段

验证Verify
目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全。
主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。

准备prepare

为类变量分配内存并且设置该类变量的默认初始值

public class HelloApp {
    private static int a  = 1;//准备阶段为0,在下一个阶段,也就是初始化阶段才1

    public static void main(String[] args) {
        System.out.println(a);
    }
}

上面的变量a在准备阶段会赋初始值,但不是1,而是0
这里不包含用final修饰的static,因为final在编译的时候就会分配了,在准备阶段会显示初始化;
这个不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到java堆中。

Resolve

将常量池内的符号引用转换为直接引用的过程。
事实上,解析操作往往会伴随JVM在执行初始化之后再执行。
符号引用就是一组符号来描述所引用的目标。符号引用的字面量形式明确定义再《java虚拟机规范》的class文件格式中。直接引用就是直接指向目标的指针,相对偏移量或一个间接定位到目标的句柄。
解析动作主要争对类或接口,字段,类方法,接口方法,方法类型。对应常量池中的CONSTANT Class info,CONSTANT Fielder info , CONSTANT Methodref info等

初始化阶段

初始化阶段就是执行类构造器法()的过程
此方法不需要定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。

  • 也就是说,当我们代码中包含static变量的时候,就会有clinit方法
  • 构造器方法中指令按语句再源文件中出现的顺序执行。
  • ()不同于类的构造器,若该类具有父类,JVM会保证子类的()执行前,父类的()已经执行完毕。
  • 任何一个类在声明后,都有生成一个构造器,默认为空构造器
    在这里插入图片描述关于涉及到父类时候的变量赋值过程
    在这里插入图片描述我们输出的结果为2,也就是说首先加载ClinitTest1的时候,会找到main方法,然后执行Son的初始化,但是Son的初始化,但是Son继承了Father,因此还需要执行Father的初始化,同时将A赋值为2,我们通过反编译得到Father的加载过程,首先我们看到原来的值被赋值为1,然后又被赋值为2,最后返回、

类加载器的分类

JVM支持两种类型的类加载器,分别为引导类加载器和用户自定义加载器。
从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是java虚拟机规范却没有这么定义,而是将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器。
无论类加载器的类型如何划分,在程序中我们最常见的类加载器始终只有3个。
在这里插入图片描述这里的四者之间是包含关系,不是上层和下层,也不是子系统的继承关系,获取它不同的加载器。

虚拟机自带的加载器

1.bootstrap class loader
它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader 加载位置是rt.jar
2.extensions class loader
3.application class loader

双亲委派机制

当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。
在这里插入图片描述

双亲委派机制的作用

1、防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
2、保证核心.class不能被篡改。通过委托方式,不会去篡改核心.clas,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值