·被访问类C不是public的,但是它与访问类D处于同一个包中。
2.字段解析
首先将会对字段表内class_index[插图]项中索引的CONSTANT_Class_info符号引用进行解析,也就是字段所属的类或接口的符号引用;
3.方法解析
先解析出方法表的class_index[插图]项中索引的方法所属的类或接口的符号引用,如果解析成功,那么我们依然用C表示这个类。
1)由于Class文件格式中类的方法和接口的方法符号引用的常量类型定义是分开的,如果在类的方法表中发现class_index中索引的C是个接口的话,那就直接抛出
java.lang.IncompatibleClassChangeError异常。
2)如果通过了第一步,在类C中查找是否有简单名称和描述符都与目标相匹配的方法,如果有则返回这个方法的直接引用,查找结束。
3)否则,在类C的父类中递归查找是否有简单名称和描述符都与目标相匹配的方法,如果有则返回这个方法的直接引用,查找结束。
4)否则,在类C实现的接口列表及它们的父接口之中递归查找是否有简单名称和描述符都与目标相匹配的方法,如果存在匹配的方法,说明类C是一个抽象类,这时候查找结束,抛出
java.lang.AbstractMethodError异常。
5)否则,宣告方法查找失败,抛出
java.lang.NoSuchMethodError。最后,如果查找过程成功返回了直接引用,将会对这个方法进行权限验证,如果发现不具备对此方法的访问权限,将抛出java.lang.IllegalAccessError异常。
4.接口方法解析
方法解析类似
JDK 9中增加了接口的静态私有方法,也有了模块化的访问约束,所以从JDK 9起,接口方法的访问也完全有可能因访问权限控制而出现
java.lang.IllegalAccessError异常。
初始化
初始化阶段就是执行类构造器 ()方法的过程。
· ()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序决定的,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。
()方法与类的构造函数(即在虚拟机视角中的实例构造器 ()方法)不同,它不需要显式地调用父类构造器,Java虚拟机会保证在子类的 ()方法执行前,父类的 ()方法已经执行完毕。因此在Java虚拟机中第一个被执行的 ()方法的类型肯定是java.lang.Object。·由于父类的 ()方法先执行,也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作。
类加载器
对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。
比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个Java虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。
这里所指的“相等”,包括代表类的Class对象的equals()方法、isAssignableFrom()方法、isInstance()方法的返回结果,也包括了使用instanceof关键字做对象所属关系判定等各种情况。
从java虚拟机角度看有俩种不同的类加载器:
一:启动类加载器(Bootstrap ClassLoader) C++实现
二:所有其他的类加载器(全部都继承自抽象类java.lang.ClassLoader) java实现
从开发人员角度看:
启动类加载器Bootstrap ClassLoader
作用:负责将存放在 lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机中。启动类加载器无法被java程序直接引用,用户在编写自定义类加载时,如果需要把加载请求委派给引导类加载器,那直接使用null代替即可,
扩展类加载器Extension ClassLoader
这个加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载 libext目录中的,或者被java.ext.dirs系统变量所指定的路径的所有类库,开发者可以直接使用扩展类加载器
应用程序加载器Application ClassLoader
这个类加载器是由sun.misc.Launcher$AppClassLoader实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器。如果应用程序中没有自定义自己的类加载器,一般情况下这个就是程序中默认的类加载器。