我们都知道java文件经过javac编译行程java.class文件,但是对于之后的事却了解甚少,现在就就要探究一下java里的编译环境
类加载器
通过编译后行程的java.class文件之后,下一步是需要经过类加载器,类加载器分为一下几种,从上至下一次分为:
-
BootstrapClassLoader(启动类加载器)
它的位置位于我们的jre目录的lib下的rt.jar,里面存放的java底层的包,一般不修改里面的东西,一旦出错则整个java就都崩盘
-
ExtClassLoader (标准扩展类加载器)
它位于jre下的lib的ext目录,可以修改里面的类
-
applicationClassLoader(系统类加载器)
-
CustomClassLoader(用户自定义类加载器)
public class Car {
public static void main(String[] args) {
Car car1 = new Car();
Car car2 = new Car();
Car car3 = new Car();
//比较地址
System.out.println(car1.hashCode());
System.out.println(car2.hashCode());
System.out.println(car3.hashCode());
//获取他们的类加载器
Class<? extends Car> aClass1 = car1.getClass();
Class<? extends Car> aClass2 = car1.getClass();
Class<? extends Car> aClass3 = car1.getClass();
//比较类加载器,顺便打印一下他们的hashcode
System.out.println(aClass1.getClassLoader()+" code:"+aClass1.hashCode());
System.out.println(aClass2.getClassLoader()+" code:"+aClass2.hashCode());
System.out.println(aClass3.getClassLoader()+" code:"+aClass3.hashCode());
//查看加载器类型
System.out.println(aClass1.getClassLoader());
System.out.println(aClass1.getClassLoader().getParent());
System.out.println(aClass1.getClassLoader().getParent().getParent());
}
}
输出结果
41359092
149928006
713338599
sun.misc.Launcher$AppClassLoader@18b4aac2 code:1555009629
sun.misc.Launcher$AppClassLoader@18b4aac2 code:1555009629
sun.misc.Launcher$AppClassLoader@18b4aac2 code:1555009629
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@a09ee92
null
总结:
类:模板
类加载器:加载类
实体类:根据类(模板)通过类加载器生成
因此他们的类加载器都是同一个,并且他的父加载器是一层一层往上的
双亲委派机制
要想知道他们的工作历程,我们可以通过下图来观察
加载任务自底向上传到,我们所定义的类一般是在applicationClassLoader上
如果我们定义了一个String类,位于java.lang包,我们都知道java的lang包下也有String类,那么由上图可知他加载的是内置的String,因为他存在于rt.jar下,是BootstrapClassLoader层的
这就是双亲委派机制,目的是让jre(java运行环境)变得更加安全,自定义类不能优先于内置类进行