JVM类加载器知识框架讲解

最近在看jvm的东东,东西有点多,看的有点蒙,就先把理解了的东西记录下来,梳理一下,本篇是关于jvm类加载器的

类加载器

Java自带的类加载器有三种

  • BootstrapClassLoader(C++编写) 包含了Java的基础核心类库(比如java包下的)
  • ExtClassLoader(java编写) 包含了Java的扩展类库(比如javax包下的)
  • AppClassLoader(java编写) 用来加载咱们开发人员写的Class

还有一种用户自定义的(这种有争议)

通过继承重写这个方法来实现,这种目前我没见过公司用过
在这里插入图片描述
这里可以看到classloader的源码,它本身就是abstract的,意味着就是留给我们继承用的,继承过后就可以根据自己公司业务进行DIY,但我目前是没见过这种用法

类加载器四大种类就这么结束了感觉有点水,来几段代码解释一下:

public class Test02 {
    public static void main(String[] args) {
        Object o = new Object();
        System.out.println(o.getClass().getClassLoader());
        System.out.println(o.getClass().getClassLoader().getParent());
        System.out.println(o.getClass().getClassLoader().getParent().getParent());
    }
}

运行结果:

null
Exception in thread "main" java.lang.NullPointerException
	at test.Test02.main(Test02.java:9)

按照我刚的说法,object的类加载器应该是Bootstrap吧,那为啥这里打个null出来呢?

这里解释一下,bootstrapClassloader,打印出来就是null,因为它是先于所有类库加载的(不然它怎么加载基础类库),那后面两行就好解释了,null调用任何方法都是空指针

再来看这个

public class Test02 {
    public static void main(String[] args) {
        Test02 test02 = new Test02();
        System.out.println(test02.getClass().getClassLoader());
        System.out.println(test02.getClass().getClassLoader().getParent());
        System.out.println(test02.getClass().getClassLoader().getParent().getParent());
    }
}

运行结果:

sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1fb3ebeb
null

很清晰了吧,第一个是用户加载器,第二个是用户加载器的爹,也就是ExtClassloader,再上去就是BootstrapClassLoader,也就是用户加载器的爷爷

双亲委派机制

你肯定听过这个名词,但是却不一定知道是个啥

先来看概念(来自wiki):

双亲委派:当一个类加载器接收到类加载请求时,会先请求其父类加载器
加载,依次递归,当父类加载器无法找到该类时(根据类的全限定
名称),子类加载器才会尝试去加载。

看完这段是不是觉得还不如不看, 因为还是很懵逼(狗头)

没事没事,先给你转成人话,然后再来一段代码你就明白了:

当类加载器加载一个类时,会从爷爷(Bootstrap加载的类库)开始往下
找,如果有,执行,如果没有就找爹(Ext加载的类库),如果有,
执行,没有就找儿子(用户写的类库),如果有执行,如果没有,
默认情况下报ClassNotFound异常

现在可能有人说,听懂了,但是,有啥用啊?

众所周知,String是不可以被继承的,那我是否可以写一个叫做String的类呢?又能否把这个String放在一个自己写的java.lang包下呢?

来看代码:

package java.lang;

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

再附一张包结构图:
在这里插入图片描述
可以看到,我手动创建了一个String类,那我现在运行一下main。

运行结果:

错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
   public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application

仔细看:错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为: public static void main(String[] args)

这不是睁着眼睛说瞎话吗?
我明明有main,而且就是这么写的

其实这就是双亲委派机制,我虽然运行了我写的java.lang.String里的main,但是实际上JVM运行的确是java自带的爷爷(BootstrapClassloader加载的类库)里的java.lang.String,那里面当然没有main

那么到这里应该就很清晰了,双亲委派机制就是为了防止咱们乱搞而存在的- -

保证了沙箱安全,也就是咱们写的代码无法污染java原生的代码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LanceQiPing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值