基础知识
进制
十进制转二进制
方法为:十进制数除2取余法,即十进制数除2,余数为权位上的数,得到的商值继续除2,依此步骤继续向下运算直到商为0为止。
二进制转十进制
方法为:把二进制数按权展开、相加即得十进制数。
二进制转八进制
方法为:3位二进制数按权展开相加得到1位八进制数。(注意事项,3位二进制转成八进制是从右到左开始转换,不足时补0)。
八进制转成二进制
方法为:八进制数通过除2取余法,得到二进制数,对每个八进制为3个二进制,不足时在最左边补零。
二进制转十六进制
方法为:与二进制转八进制方法近似,八进制是取三合一,十六进制是取四合一。(注意事项,4位二进制转成十六进制是从右到左开始转换,不足时补0)
十六进制转二进制
方法为:十六进制数通过除2取余法,得到二进制数,对每个十六进制为4个二进制,不足时在最左边补零。
十进制与八进制与十六进制之间的转换
十进制转八进制或者十六进制有两种方法
第一:间接法—把十进制转成二进制,然后再由二进制转成八进制或者十六进制。这里不再做图片用法解释。
第二:把十进制转八进制或者十六进制按照除8或者16取余,直到商为0为止。
八进制或者十六进制转成十进制
方法为:把八进制、十六进制数按权展开、相加即得十进制数。
不同语言能在JVM上运行的本质(.class)
认识字节码文件
手动解析字节码文件
魔数(标志):ca fe ba be
次版本号:00 00
主版本号:00 34 ----->52 jdk1.8
常量池个数(真实的常量池个数 = 字节码文件中的常量池个数 - 1,常量池最小的index不是0,是1 ):00 23-----> 35
解析常量池:
1.0a 00 05 00 16
tag:0a method
class_index: 00 05 5
name_and_type: 00 16 22
2.09 00 17 00 18
tag:09 fiel
class_index: 00 17 23
name_and_type: 00 18 24
3.0a 00 19 00 1a
tag:0a method
class_index: 00 19 25
name_and_type: 00 1a 26
4.07 00 1b
tag:07 class
class_index: 00 1b 27
5.07 00 1c
tag:07 class
class_index: 00 1c 28
6.01 00 06 3c
tag:01
length: 00 06 6
bytes: 1c 28
7.69 6e 69 74
tag:69
length: 6e 69
bytes: 74
8.3e 10 00 03
tag:3e
length: 10 00
bytes: 03
9.28 29 56 01
tag:
length:
bytes:
.......
accesss_flag:0021 plubic
this_class:00 04
super_class:00 05
接口数量:00 00
成员属性:00 00
field_info{
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count]
}
成员方法:00 02
methods_info[
method_info {
u2 access_flags; 00 01 access_flags 项的值是用于定义当前方法的访问权限和基本属性的掩码标志
u2 name_index; 00 09 指向常量池
u2 descriptor_index; 00 0A 方法描述符 V代表返回值是void 其他跟字段描述符一样
u2 attributes_count; 00 01 code属性个数
attribute_info attributes[attributes_count];
attributes[
Code_attribute {
u2 attribute_name_index; 00 0B 指向常量池,表示字符串code
u4 attribute_length; 00 00 00 2F attribute_length这个意思是下面所有的字节数加起来是这个数;attribute_length 项的值表示当前属性的长度,不包括开始的 6 个字节
u2 max_stack; 00 01 操作栈数量,是栈帧里面的 在任意时刻,操作数栈都会有一个确定的栈深度,一个 long 或者 double 类型的数据会占用两个单位的栈深度,其他数据类型则会占用一个单位深度
u2 max_locals; 00 01 max_locals 项的值给出了分配在当前方法引用的局部变量表中的局部变量个数
u4 code_length; 00 00 00 05 code_length 项给出了当前方法的 code[]数组的字节数
u1 code[code_length]; 2A B7 00 01 B1 code[]数组给出了实现当前方法的 Java 虚拟机字节码---方法体或者说是字节码指令
u2 exception_table_length; 00 00 异常
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count; 00 02 表示attributes数组的个数
attribute_info attributes[attributes_count];
attributes[
LineNumberTable_attribute { 为什么我知道是这个属性勒?因为00 0C指向常量池12,而12就是LineNumberTable_attribute。
u2 attribute_name_index; 00 0C
u4 attribute_length; 00 00 00 06 attribute_length 给出了当前属性的长度,不包括开始的 6 个字节
u2 line_number_table_length; 00 01 说明line_number_table数组的个数,而line_number_table里的元素就是下面的这个{}
line_number_table[line_number_table_length];
[
{
u2 start_pc; 00 00 code数组的索引
u2 line_number; 00 08 line_number 项的值必须与源文件的行数相匹配
}
]
}
LocalVariableTable_attribute {
u2 attribute_name_index; 00 0D 指向常量池
u4 attribute_length; 00 00 00 0c 当前属性的长度,不包括开始的 6 个字节
u2 local_variable_table_length; 00 01 local_variable_table[]数组的成员个数
local_variable_table[local_variable_table_length];
[
{
u2 start_pc; 00 00 start_pc是local_variable_table的下标
u2 length; 00 05 length两种意思。具体的看书
u2 name_index; 00 0E 指向常量池,表示一个局部变量的有效的非全限定名
u2 descriptor_index; 00 0F 字段描述符
u2 index; 00 00 index为此局部变量在当前栈帧的局部变量表中的索引
}
]
}
]
}
]
}
类属性:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length]
}