类加载器ClassLoader
类加载器子系统作用
- 类加载器子系统负责从文件系统或者网络中加载class文件的加载,至于是否运行是由执行引擎决定的。
- 加载的类的信息存在方法区中,还有常量池
类的加载过程
- 加载:通过一个类的全类名获取此类的二进制字节流,在方法区存放该字节流代表的静态存储结构,然后生成一个Class对象,作为方法区各种数据的访问入口
- 链接
- 验证:保证字节码的合法性
- 准备:为类变量分配内存,并赋初始值,注意不包含final修饰的static,因为final在编译的时候就分配了,准备阶段会显式初始化,不会为实例变量分配初始化
- 解析:将常量池的符号引用转变为直接引用的过程
- 初始化:初始化就是执行clinit方法的过程,此方法不需要定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块的语句合并而来,如果没有这些操作则不会有该方法。
类加载器分类
- 引导类加载器(bootstrap classloader)是用c/c++实现的,用来加载java的核心类库 jre/lib/rt.jar 加载扩展类加载器和系统类加载器 只能加载java,javax,sun开头的类
- 扩展类加载器(extend classloader)加载jre/lib/ext下的包,java写的,由launcher实现,如果用户自己的jar放在此目录下,也会加载
- 系统类加载器(app classloader)java写的,有sun.misc.launcher实现,负责加载环境变量或系统属性java.class.path指定路径下的类,程序中的默认加载器,一般来说,java的类都是由该加载器加载,可以通过classloader.getsystemclasslo方法获取到该加载器
- 为什么要有自定义类加载器呢:1.隔离加载类 2.修改类加载的方式 3. 扩展加载源 4. 防止源码泄漏 继承classloader
双亲委派机制
- 如果一个类需要加载,他并不会直接加载,而是委托给父类的加载器,如果父类的加载器还存在父类,则继续委托,知道最终层的启动类加载器,如果父类加载器可以加载,就会加载,否则子类加载器才会尝试加载,这就是双亲委派机制
- 为什么?1. 避免重复加载 2.保护程序安全,防止核心api被篡改
沙箱安全机制
- 防止恶意代码污染java源代码,沙箱,其实就是限制环境,比如我定义了一个类名为String所在包为java.lang,因为这个类本来是属于jdk的,如果没有沙箱安全机制的话,这个类将会污染到我所有的String,但是由于沙箱安全机制,所以就委托顶层的bootstrap加载器查找这个类,如果没有的话就委托extsion,extsion没有就到aapclassloader,但是由于String就是jdk的源代码,所以在bootstrap那里就加载到了,先找到先使用,所以就使用bootstrap里面的String,后面的一概不能使用,这就保证了不被恶意代码污染,限制了string类是由bootstrap加载