1、java类的加载机制
(1)虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成可以被java虚拟机直接使用的java类型。
执行过程:可以分为5步
(1)通过全类名获取类的二进制字节流,将类的静态存储结构转化为方法区的运行时数据结构,在内存中生成类的class对象,作为方法区数据的入口。
(2)验证:对文件格式,元数据,字节码,符号引用等验证正确性
(3)准备:在方法区内为类变量分配内存并设置为0值
(4)解析:将符号引用转化为直接引用
(5)初始化:执行类构造器clinit方法,真正初始化。
2、什么是类加载机制
(1)Class文件中描述的各类信息都需要加载到虚拟机中才能使用,虚拟机把描述类数据从class文件加载到内存,并对数据进行校验、解析和初始化,最终形成可以被java虚拟机直接使用的java类型,这个过程叫做虚拟机的类加载机制。
3、描述一下JVM加载class文件的原理机制
(1)java中所有的类,都需要类加载器加载到JVM中才能运行。类加载器本身也是一个类,而他的工作就是把class文件从硬盘中读取到内存中。在写程序的时候,我们不需要关=关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显示的加载所需要额度类。
(2)类的装载方式有两种:
①隐式装载:程序在运行过程中,当碰到通过new等方式生成对象时,隐式调用类装载器加载对应的类到JVM中
②显示装载:通过class.forname()等方法,显示加载需要的类
java类的加载是动态的,不会一次把所有的类全部加载后执行,而是保证程序运行的基础类完全加载到JVM当中,至于其他类,需要的时候才加载。
4、什么是类加载器,类加载器有哪些
对于任何一个类,都需要由它的类加载器和这个类本身一同确立在JVM中的唯一性,每一个类加载器,都有一个独立的类名称空间。类加载器就是实现通过类的全限定名,获取该类的二进制字节流的代码块。
主要有4种类加载器
(1)启动类加载器(BootStrap ClassLoader):是虚拟机中的一部分,用来加载java的核心库,用于提供JVM自身所需要的类,并不继承于java.lang.ClassLoader,没有父加载器。出于安全考虑。BootStrap启动类加载器只包含java,javax,sun等开头的类
(2)扩展类加载器(Extension ClassLoader):\lib\ext目录或Java. ext. dirs系统变量指定的路径中的所有类库
(3)系统类加载器(Application ClassLoader):负责加载环境变量classpath或系统属性java.class。path指定路径下的类库,父类加载器为扩展类加载器。一般情况,如果我们没有自定义类加载器,默认使用系统类加载器。
**(4)用户自定义类加载器:**通过继承java.lang.ClassLoader类的方式实现。
5、java的类的加载流程
**(1)加载:**通过一个类的全限定类名获取定义类的二进制字节流,将字节流所代表的的静态存储结构转化为方法区的运行时数据区,在内存中生成对应该类的Class实例,作为方法区这个类的数据访问入口。
**(2)验证:**检查加载的class文件的正确性。(如果java虚拟机不检查输入的字节流,可能因为载入错误或者恶意企图的字节流导致系统受到攻击)
**(3)准备:**为静态变量分配内存空间并设置零值。(该阶段进行内存分配的仅包括类变量,不包括实例变量,类变量分配到方法区,实例变量会随着对象一起被分配到堆中,不包含被final修饰的变量,因为final修饰的变量在编译的时候就分配了,准备阶段会显式初始化 )
**(4)解析:**虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用可以理解为一个标示,直接引用是直接指向内存中的地址。
6、什么是双亲委派模型
前提:java虚拟机对class文件采用的是按需加载的方式,也就是说需要使用该类的时候才会将它的class文件加载到内存中生成class对象。而且加载某个类的class文件时,java虚拟机采用的是双亲委派模式,即把请求交给父类处理,它是一种任务委派模式。
**双亲委派模型:**如果一个类加载器收到类加载的请求,他首先不会自己去加载这个类,而是把这个请求交给父类加载器去完成,每一层类加载器都是如此,这样所有的加载请求都会被传送到顶层的启动类加载器中,如果父类加载器可以完成加载任务,就成功返回,如果父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。
为什么使用双亲委派机制
(1)双亲委派机制可以使类的加载出现层级,父类加载器加载过的类,子类加载器不会重复加载,可以防止类的重复加载。
(2)使得类的加载出现优先级,防止核心API被篡改
如何打破双亲委派模型
首先破坏双亲委派模型,第一步就是要实现自定义类加载器,集成 class 类,实现自定义类加载要实
现两个方法 findclass 方法和 loadclass 方法,首先呢 loadclass 方法如果没有重写,那就是默认的双亲
委派模型,如果重写了就可以打破。而 findclass 方法,是为了保证在父类加载器完成不了类加载请
求的时候,这个方法需要完成类加载的逻辑。所以打破双亲委派就重写 loadclass 方法。
Tomcat为啥要破坏
Tomcat 通过自定义类加载器 WebappClassLoader 只加载自己目录下的 class 文件,即重写 loadClass()方法,不传递给父类加载器。
为了在部署多个独立项目时,项目能加载到相同类库的不同版本。默认的类加载机制无法加载同一
类库的不同版本。