最近在看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原生的代码