Chap 6 类文件结构
1.Class文件是一组以8位为基础的二进制流。其存储数据只使用无符号数(以u1、u2、u4和u8分别代表1/2/4和8个字节的无符号数)和表(由多个无符号数和其他表构成并且以_info结尾)两种结构。
2.class的结构包括:
A.魔数:class文件的头四个字节位魔数:0XCAFEBABE。
B.Class文件版本号:分为Minor版本和Major版本,都是四个字节。其中JDK1.0的大版本号是45,大版本号依次递增。
C.常量池:class文件的资源仓库。首先是一个u2类型的数据表示常量池容量计数值。然后是不同类型结构的数据。
D.访问标志:用于标识一些类或者接口的访问信息。如class是类还是接口,访问类型等信息。
E.类索引、父类索引与接口索引集合:用于确定类的继承关系。类索引用于确定类的全限定名,父类索引用于确定类的父类全限定名。接口索引集合用来描述类实现了接口的集合。
F.字段表集合:用于描述接口或者类中声明的变量。包括字段访问作用域(public、private、protected)、是否static修饰、是否final、是否并发可见volatile、是否可被序列化transient等。
G.方法表集合:类似于字段表集合,用于描述接口或者类中声明的方法。
H.属性表集合:在class文件,字段表,方法表都可以携带自己的属性表集合(像前面方法表的时候就用到“code”这个属性表)以用于描述某些场景专有的信息。例如code表示java代码变异成的字节码指令,constantValue表示final关键字定义的常量池等。
Chap 7 虚拟机类加载机制
1.类的生命周期:LVPRIUU(加载L-验证V-准备P-解析Resolution-初始化I-使用U-卸载U)。
2.有且只有5种必须初始化(加载、验证、准备自然需要再次之前进行)的情况:
A.遇到new/getstatic/putstatic或invokestatic指令时必须进行初始化。也就是使用new创建实例、读取或设置类的静态字段(!!!被final修饰的字段已经在编译期把结果放入常量池!!!)、调用一个类的静态方法。
B.使用java.lang.reflect包的方法进行反射调用的时候必须初始化。
C.初始化一个类的时候,发现其父类没有初始化,首先触发父类初始化。
D.虚拟机启动时需要制定一个执行的主类,虚拟机会先初始化这个主类。
E.使用JDK1.7的动态语言支持时。
3.被动引用的例子:
A.通过子类引用父类的静态字段只会触发父类的初始化而不会触发子类的初始化。
B.使用new生成对象数组的时候不会触发初始化。
C.调用final的静态变量不会触发初始化,final类型的静态变量在编译器已经存储为常量。
PS:这里的初始化指的是类中static代码块、static变量声明并定义等语句。
4.加载过程中类加载器的工作:
A.通过类的权限定名获取类的二进制字节流。
B.将字节流所代表的静态存储结构转化为方法区的运行时数据结构。
C.在内存中生成一个代表这个类的对象,作为方法区这个类的各种数据的访问入口。
PS:数组类本身不通过类加载器创建,而是由Java虚拟机直接创建。
5.验证:确保class文件字节流中的信息符合当前虚拟机的要求,如文件格式、元数据、字节码、符号引用等验证工作。
6.准备:正式为类变量分配内存并设置类变量初始值的阶段。理解:public static int value=123;准备阶段设置value的值为int类型默认值0,然后初始化阶段,存储在类构造器<clinit>方法中的变量123赋值给value。
7.解析:虚拟机将常量池内的符号引用(用符号描述所引用的目标)替换为直接引用(可以是指向目标的指针、相对偏移量或一个能简介定位到目标的句柄)的过程。
8.初始化:执行类构造器<clinit>()方法的过程。
A.该方法是编译器自动收集类中所有类变量(static)的赋值动作和静态语句块中的语句合并产生的,比阿尼器收集的顺序是由语句在源文件出现的顺序决定的。静态语句块中只能访问到定义在静态语句块之前的变量,定义在他之后的变量,前面的静态语句块可以复制,不能访问。
B.该方法与类的构造方法不同,不要显示调用父类构造器,虚拟机保证在子类的clinit方法执行之前,父类的clinit方法已经执行完毕。
C.由于父类的clinit方法先执行,表示父类的静态语句块优先于子类的变量赋值操作。
D.该方法对于类和接口不是必须的,如果类中没有静态语句块和变量的赋值操作,那么编译器不产生该类的clinit方法。
E.接口中不能使用静态语句块,但仍然有变量初始化的赋值操作,因此会生成clinit方法。但是接口的clinit方法不需要执行父类的clinit方法,调用接口的实现类的初始化也不会调用接口的clinit方法。
10.类加载器:
A.启动类加载器:Bootstrap ClassLoader,加载java_home/lib下或者-Xbootclasspath指定的类。
B.扩展类加载器:Extension ClassLoader,加载java_home/lib/ext目录或者java.ext.dirs系统变量指定目录的类。
C.应用程序类加载器:Application ClassLoader,加载用户类路径ClaaaPath上指定的类库,如果类没有自定义实现类加载器,就是程序中默认的类加载器。
Chap 8 虚拟机字节码执行引擎
1.栈帧的结构:局部变量表、操作数栈、动态链接和方法返回地址。
2.局部变量表用于存放方法参数和方法内部定义额局部变量。
3.操作数栈用于记录代码指令的操作。
4.静态分派:Human man = new Man(); Human women = new Women();say(man)和say(women)中调用say(Human)参数的函数,这便是静态分派。
5.动态分派:例如重写方法,动态的使用。
Chap 9 类加载及执行子系统额案例与实战
略
1.Class文件是一组以8位为基础的二进制流。其存储数据只使用无符号数(以u1、u2、u4和u8分别代表1/2/4和8个字节的无符号数)和表(由多个无符号数和其他表构成并且以_info结尾)两种结构。
2.class的结构包括:
A.魔数:class文件的头四个字节位魔数:0XCAFEBABE。
B.Class文件版本号:分为Minor版本和Major版本,都是四个字节。其中JDK1.0的大版本号是45,大版本号依次递增。
C.常量池:class文件的资源仓库。首先是一个u2类型的数据表示常量池容量计数值。然后是不同类型结构的数据。
D.访问标志:用于标识一些类或者接口的访问信息。如class是类还是接口,访问类型等信息。
E.类索引、父类索引与接口索引集合:用于确定类的继承关系。类索引用于确定类的全限定名,父类索引用于确定类的父类全限定名。接口索引集合用来描述类实现了接口的集合。
F.字段表集合:用于描述接口或者类中声明的变量。包括字段访问作用域(public、private、protected)、是否static修饰、是否final、是否并发可见volatile、是否可被序列化transient等。
G.方法表集合:类似于字段表集合,用于描述接口或者类中声明的方法。
H.属性表集合:在class文件,字段表,方法表都可以携带自己的属性表集合(像前面方法表的时候就用到“code”这个属性表)以用于描述某些场景专有的信息。例如code表示java代码变异成的字节码指令,constantValue表示final关键字定义的常量池等。
Chap 7 虚拟机类加载机制
1.类的生命周期:LVPRIUU(加载L-验证V-准备P-解析Resolution-初始化I-使用U-卸载U)。
2.有且只有5种必须初始化(加载、验证、准备自然需要再次之前进行)的情况:
A.遇到new/getstatic/putstatic或invokestatic指令时必须进行初始化。也就是使用new创建实例、读取或设置类的静态字段(!!!被final修饰的字段已经在编译期把结果放入常量池!!!)、调用一个类的静态方法。
B.使用java.lang.reflect包的方法进行反射调用的时候必须初始化。
C.初始化一个类的时候,发现其父类没有初始化,首先触发父类初始化。
D.虚拟机启动时需要制定一个执行的主类,虚拟机会先初始化这个主类。
E.使用JDK1.7的动态语言支持时。
3.被动引用的例子:
A.通过子类引用父类的静态字段只会触发父类的初始化而不会触发子类的初始化。
B.使用new生成对象数组的时候不会触发初始化。
C.调用final的静态变量不会触发初始化,final类型的静态变量在编译器已经存储为常量。
PS:这里的初始化指的是类中static代码块、static变量声明并定义等语句。
4.加载过程中类加载器的工作:
A.通过类的权限定名获取类的二进制字节流。
B.将字节流所代表的静态存储结构转化为方法区的运行时数据结构。
C.在内存中生成一个代表这个类的对象,作为方法区这个类的各种数据的访问入口。
PS:数组类本身不通过类加载器创建,而是由Java虚拟机直接创建。
5.验证:确保class文件字节流中的信息符合当前虚拟机的要求,如文件格式、元数据、字节码、符号引用等验证工作。
6.准备:正式为类变量分配内存并设置类变量初始值的阶段。理解:public static int value=123;准备阶段设置value的值为int类型默认值0,然后初始化阶段,存储在类构造器<clinit>方法中的变量123赋值给value。
7.解析:虚拟机将常量池内的符号引用(用符号描述所引用的目标)替换为直接引用(可以是指向目标的指针、相对偏移量或一个能简介定位到目标的句柄)的过程。
8.初始化:执行类构造器<clinit>()方法的过程。
A.该方法是编译器自动收集类中所有类变量(static)的赋值动作和静态语句块中的语句合并产生的,比阿尼器收集的顺序是由语句在源文件出现的顺序决定的。静态语句块中只能访问到定义在静态语句块之前的变量,定义在他之后的变量,前面的静态语句块可以复制,不能访问。
B.该方法与类的构造方法不同,不要显示调用父类构造器,虚拟机保证在子类的clinit方法执行之前,父类的clinit方法已经执行完毕。
C.由于父类的clinit方法先执行,表示父类的静态语句块优先于子类的变量赋值操作。
D.该方法对于类和接口不是必须的,如果类中没有静态语句块和变量的赋值操作,那么编译器不产生该类的clinit方法。
E.接口中不能使用静态语句块,但仍然有变量初始化的赋值操作,因此会生成clinit方法。但是接口的clinit方法不需要执行父类的clinit方法,调用接口的实现类的初始化也不会调用接口的clinit方法。
F.clinit是线程安全的。
PS:clinit是类初始化生成的方法,linit是对象初始化生成的方法,如非静态变量的初始化。
9.类与类加载器:加载器不同,同一个被加载的类也是不相同的。类加载器使用双亲委派模型:当一个类加载器受到类加载请求时,首先委派父类加载器加载,最终会委派给启动类加载器,如果父加载器无法加载,子加载器才尝试加载。10.类加载器:
A.启动类加载器:Bootstrap ClassLoader,加载java_home/lib下或者-Xbootclasspath指定的类。
B.扩展类加载器:Extension ClassLoader,加载java_home/lib/ext目录或者java.ext.dirs系统变量指定目录的类。
C.应用程序类加载器:Application ClassLoader,加载用户类路径ClaaaPath上指定的类库,如果类没有自定义实现类加载器,就是程序中默认的类加载器。
Chap 8 虚拟机字节码执行引擎
1.栈帧的结构:局部变量表、操作数栈、动态链接和方法返回地址。
2.局部变量表用于存放方法参数和方法内部定义额局部变量。
3.操作数栈用于记录代码指令的操作。
4.静态分派:Human man = new Man(); Human women = new Women();say(man)和say(women)中调用say(Human)参数的函数,这便是静态分派。
5.动态分派:例如重写方法,动态的使用。
Chap 9 类加载及执行子系统额案例与实战
略