1 功能:
a) 校验确认class文件内容有正确的结构
b) 在字节码执行之前对文件进行校验
2 具体执行过程:
a) 装载字节序列时,针对二进制数据进行校验,校验目的是确认class文件结构的合法性,如果校验失败会抛出异常
eg: 使用windowns下的copy命令去合并一个.class文件和一个jpg文件的时候,装载这个class文件的时候jvm会发现这个class文件被删改过,文件的长度也不正确,而抛出异常!
b) 扫描方法区目的是确认类能顺利编译,扫描范围为:方法区,针对语义,词法,语法进行分析
c) 字节码校验: 验证词法
c.1) 字节码流
字节码流 = 操作码+操作数
d) 符号应用校验: 即确认被引用的类,字段,方法确实存在
详细解释:
大部分JVM的实现都是使用延迟加载/动态链接,即:JVM加载类A,而A又引用B,
JVM不会加载B,而是将B相对于A的引用形式登记在符号表中,在真正使用到B时,才会将被引用类B在引用类A的符号引用名改为内存里的直接引用。
因为这个过程发生在方法区中,并且发生时间不可预测,因此这个过程也叫做动态连接。
总结下为:
1.查找被引用的类(有必要的话就加载它)
2.将符号引用替换为直接引用,例如一个指向类、字段或方法的指针,下次再需要用到被引用类的时候直接运用直接引用,不需要再去装载。
分析ClassLoader类中的loadClass方法,能找到动态连接的踪迹:
protected synchronized Class<?> loadClass(String name, boolean resolve) 02.throws ClassNotFoundException 03. { 04.// First, check if the class has already been loaded 05.Class c = findLoadedClass(name); 06.if (c == null) { 07. try { 08. if (parent != null) { 09. c = parent.loadClass(name, false); 10. } else { 11. c = findBootstrapClass0(name); 12. } 13. } catch (ClassNotFoundException e) { 14. // If still not found, then invoke findClass in order 15. // to find the class. 16. c = findClass(name); 17. } 18.} 19.if (resolve) { 20. resolveClass(c); 21.} 22.return c; 23. }
loadClass有两个参数,第一个参数是类的全限定名,第二个参数就是我们要说的重点,这个参数为true的时候表示,loadClass方法会执行resolveClass的方法,这个方法就是将类中的符号引用替换为直接引用。最终调用的方法是一个本地方法 resolveClass0。
Class.forName这个静态的方法我们也常用来加载class文件的字节码,和classLoader.loadClass(String name, boolean resolve) 有什么区别
区别就在于是否执行resolveClass这个方法
Class.forName总是承诺将符号连接进行连接和初始化
loadClass没有这样的承诺, 需要参数来具体指定是否加载
3 class文件校验器脑图: