快速入门JVM,只看这一篇就够了(二)

73 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第44天,点击查看活动详情

之前在其他平台发表过的文章,今天分享在掘金,跟大家一起学习~

4.类加载器子系统

在这里插入图片描述

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

注意到:虚拟机自带的加载器:

  • 引导类加载器(bootstrap),底层是C++,出厂就有的,即从1.0版本开始就有,像Object、String类就由此加载器加载
  • 扩展类加载器(Extension),由Java扩展,为满足日益增长的需要
  • 应用程序类加载器(AppClassLoader),Java,也叫做系统类加载器,加载当前应用的classpath的所有类

此外,还有用户自定义加载器,为Java.lang.ClassLoader的子类,用户可以自定义类的加载方式。 可以用下面的图来表示几个类加载器之间的关系 在这里插入图片描述

为什么会有向上指的指针呢?这就要牵扯到一个重要的机制:双亲委派机制。这是啥意思?用一个案例来解释。假设我在src目录下建立了一个java.lang包,然后在该包了定义了一个类String,然后编写main方法,里面输出“hello world”,语法上没有任何错误,但程序就是启动不来。这是为啥?原因是双亲委派机制保证了Java体系的安全性,即类加载器要加载这个自定义的String类,要先从Bootstrap ClassLoder开始加载起,如果Bootstrap ClassLoader找到了java.lang.String,就加载这个类,很显然这个类是Java的rt.jar包中的,立马就找到了;因此也就轮不到System ClassLoader来加载我自定义的这个String类了。 下面给出总结: 当一个类收到了类加载请求,它首先不会尝试自己加载这个类,而是把这个请求委派给父类完成,每一个层次类加载器都是如此,因此所有的加载请求都是传送到Bootstrap类加载器中,只有当父类加载器反馈自己无法完成这个请求时(即在它的加载路径下没有找到所需要加载的Class),子类加载器才会尝试去加载。采用双亲委派的一个好处就是,如加载rt.jar包中的类java.lang.Object时,不管是哪个加载器加载这个类,最终都是委托给顶层的Bootstrap ClassLoader进行加载,这样就保证了使用不同的类加载器最终得到的都是同一个Object对象。