Java类加载器子系统

Java类加载器子系统

1、类加载的过程

类加载的过程包括了加载,验证,准备,解析和初始化这5个步骤。

①. 加载:找到字节码文件,读取到内存中。类的加载方式分为隐式加载和显示加载两种。隐式加载指的是程序在使用new关键词创建对象时,会隐式的调用类的加载器把对应的类加载到jvm中。显示加载指的是通过直接调用class.forName()方法来把所需的类加载到jvm中。

②. 验证:验证此字节码文件是不是真的是一个字节码文件,毕竟后缀名可以随便改,而内在的身份标识是不会变的.在确认是一个字节码文件后,还会检查一系列的是否可运行验证,元数据验证,字节码验证,符号引用验证等。Java虚拟机规范对此要求很严格,在Java 7的规范中,已经有130页的描述验证过程的内容。

③. 准备:为类中static修饰的变量分配内存空间并设置其初始值为0或null。可能会有人感觉奇怪,在类中定义一个static修饰的int,并赋值了123,为什么这里还是赋值0。因为这个int的123是在初始化阶段的时候才赋值的,这里只是先把内存分配好。但如果你的static修饰还加上了final,那么就会在准备阶段就会赋值。

④. 解析:解析阶段会将java代码中的符号引用替换为直接引用。比如引用的是一个类,我们在代码中只有全限定名来标识它,在这个阶段会找到这个类加载到内存中的地址。

⑤. 初始化:如刚才准备阶段所说的,这个阶段就是对变量的赋值的阶段。

如上过程都是在JVM执行的过程中自己完成的,我们无需干涉。

2、类与类加载器

每一个类,都需要和它的类加载器一起确定其在JVM中的唯一性。换句话说,不同类加载器加载的同一个字节码文件,得到的类都不相等。我们可以通过默认加载器去加载一个类,然后new一个对象,再通过自己定义的一个类加载器去加载同一个字节码文件,拿前面得到的对象去instanceof,会得到的结果是false。

3、双亲委派机制

JVM中内置的类加载器:
类加载器子系统

类加载时使用了双亲委派模式:

加载规则,优先使用爷爷(启动类加载器)加载,如果没有加载到再使用它爹(扩展类加载器)加载,如果他爹也没有加载到,才到自己(应用程序类加载器或者自定义类加载器)加载,如果自己也没有加载到才报ClassNotFountException。在这过程中只要上一级加载到了,下一级就不会加载。

这么做的目的:不让我们轻易覆盖系统提供的功能,也要让我们扩展我们的功能。

类加载器一般有4种,其中前3种是必然存在的。

① 启动类加载器:加载<JAVA_HOME>\lib下的。

②扩展类加载器:加载<JAVA_HOME>\lib\ext下的。

③应用程序类加载器:加载Classpath下的。

④自定义类加载器

而双亲委派机制是如何运作的呢?

我们以应用程序类加载器举例,它在需要加载一个类的时候,不会直接去尝试加载,而是委托上级的扩展类加载器去加载,而扩展类加载器也是委托启动类加载器去加载。启动类加载器在自己的搜索范围内没有找到这么一个类,表示自己无法加载,就再让扩展类加载器去加载。同样的,扩展类加载器在自己的搜索范围内还是没有找到,就交给应用程序类加载器去加载。如果最终应用程序类加载器还是没找到,那就会直接抛出ClassNotFountException异常了。

而为什么要这么麻烦的从下到上,再从上到下呢?

这是为了安全着想,保证按照优先级加载。如果用户自己编写一个名为java.lang.Object的类,放到自己的Classpath中。没有这种优先级保证,应用程序类加载器就把这个当做Object加载到了内存中,从而会引发一片混乱。而凭借这种双亲委派机制,先一路向上委托,启动类加载器去找的时候,就把正确的Object加载到了内存中,后面再加载自行编写的Object的时候,是不会加载运行的。

结论:JDK自带的类是没法覆盖的,而引入的三方的JAR是可以自己定义相同的类来覆盖。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值