zoukankan      html  css  js  c++  java
  • 【阅读笔记】深入java虚拟机-第三部分-虚拟机执行子系统

    首先,我不是书内容的搬运工,以下内容全部为个人的真实例子!

    一个class片段

    cafe babe 0000 0033 0148 0a00 4800 bc07
    00bd 0a00 0200 bc08 0058 0b00 be00 bf0a
    00c0 00c1 0a00 c200 c30a 0048 00c4 0a00
    c500 c608 00c7 0a00 0c00 c807 00c9 0800
    ca0a 00cb 00cc 0800 cd0a 00cb 00ce 0a00
    c000 cf08 0071 0800 d00a 00d1 00d2 0800
    6f08 0070 0900 4700 d30b 00d4 00d5 0800
    d607 00d7 0a00 1a00 d80b 00d4 00d9 0b00
    da00 db08 0087 0b00 dc00 dd08 0088 0a00
    d100 de0a 00d1 00df 0800 e00a 00e1 00e2
    0a00 d100 e30a 00e4 00e5 0500 0000 0000
    0493 e00b 00dc 00e6 0800 e708 00e8 0b00
    d400 e908 00ea 0800 eb08 00ec 0700 ed0a
    0030 00bc 0900 4700 ee0b 00ef 00f0 0b00
    ef00 f10b 00ef 00f2 0a00 4700 f30b 00dc
    00f4 0a00 e400 f507 00f6 0a00 3900 bc08
    00f7 0a00 3900 f808 00f9 0a00 3900 c408
    00fa 0a00 c000 fb0a 00fc 00fd 0a00 3900
    fe07 00ff 0a00 4300 bc0a 0043 0100 0a00
    3901 0107 0102 0701 0301 000b 6958 4146
    5365 7276 6963 6501 0027 4c6e 6574 2f73
    6c77 6973 682f 717a 2f78 6166 2f73 6572
    7669 6365 2f49 5841 4653 6572 7669 6365
    3b01 0019 5275 6e74 696d 6556 6973 6962
    6c65 416e 6e6f 7461 7469 6f6e 7301 0038
    4c6f 7267 2f73 7072 696e 6766 7261 6d65
    776f 726b 2f62 6561 6e73 2f66 6163 746f
    7279 2f61 6e6e 6f74 6174 696f 6e2f 4175
    746f 7769 7265 643b 0100 0b69 5765 6253
    6572 6976 6365 0100 274c 6e65 742f 736c
    

    魔数与class文件版本

    魔数

    所有class文件里的16进制都以cafe babe开头

    版本号

    cafe babe后面的0000次版本号0033主版本号,转为10进制后,这个class的版本号为51.0

    有时候项目启动会报java.lang.UnsupportedClassVersionError: Unsupported major.minor version 51.0,后面的51.0也就是class的版本号。

    有时候需要指定版本号编译,以maven项目为例

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    

    常量池

    引用书内说法

    常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。
    字面量比较接近于Java语言层面的常量概念,如文本字符串、声明为final的常量值等。
    而符号引用则属于编译原理方面的概念,包括了下面三类常量:类和接口的全限定名(Fully Qualified Name)、字段的名称和描述符(Descriptor)方法的名称和描述符

    在本文最开始的class片段中
    0148表示常量池的数量,转换为10进制后,是328,因为常量池的索引是从1开始,也就是说有327个常量。索引0空出来有特殊的用途。

    注:只有常量池的容量计数是从1开始,其他都是从0开始

    常量池中14种常量项的结构总表

    下次列出...

    现在来分析一下上面的部分常量

    0a 00 48 00 bc

    0a => 10,类型为CONSTANT_Methodref_info
    00 48 => 72,声明方法的类描述符CONSTANT_Class_info的索引
    00 bc => 188,名称级类型描述符CONSTANT_NameAndType的索引

    07 00 bd

    07 => 7,类型为CONSTANT_Class_info
    00 bd => 189,全限定名常量的索引

    0a 00 02 00 bc

    0a => 10,类型为CONSTANT_Methodref_info
    00 02 => 2,声明方法的类描述符CONSTANT_Class_info的索引
    00 bc => 188,名称级类型描述符CONSTANT_NameAndType的索引

    08 00 58

    08 => 8,类型为CONSTANT_String_info
    00 58 => 88,字符串字面量的索引

    etc...

    • 0b 00 be 00 bf
    • 0a 00 c0 00 c1
    • 0a 00 c2 00 c3
    • 0a 00 48 00 c4
    • 0a 00 c5 00 c6
    • 08 00 c7
    • 0a 00 0c 00 c8
    • 07 00 c9
    • 08 00 ca
    • 0a 00 cb 00 cc
    • 08 00 cd
    • 0a 00 cb 00 ce
    • 0a 00 c0 00 cf
    • 08 00 71
    • 08 00 d0
    • 0a 00 d1 00 d2
    • ...

    几个utf-8编码的字符串常量

    1. 01 00 0b 69 58 41 46 53 65 72 76 69 63 65
    2. 01 00 27 4c6e 6574 2f73 6c77 6973 682f 717a 2f78 6166 2f73 6572 7669 6365 2f49 5841 4653 6572 7669 6365 3b

    注:这里用的是utf-8缩略码,即:
    从'u0001'到'u007f'之间的字符(相当于1~127的ASCII码)的缩略编码使用一个
    字节表示,
    从'u0080'到'u07ff'之间的所有字符的缩略编码用两个字节表示,
    从'u0800'到'uffff'之间的所有字符的缩略编码就按照普通UTF-8编码规则使用三个字节表示。

    01 => 类型为CONSTANT_Utf8_info
    00 0b => 长度为11的字符串
    69 58 41 46 53 65 72 76 69 63 65 => 'u0069u0058u0041u0046u0053u0065u0072u0076u0069u0063u0065' => "iXAFService"

    01 => 类型为CONSTANT_Utf8_info
    00 27 => 长度为39的字符串
    4c6e 6574 2f73 6c77 6973 682f 717a 2f78 6166 2f73 6572 7669 6365 2f49 5841 4653 6572 7669 6365 3b => 'u004cu006eu0065u0074u002fu0073u006cu0077u0069u0073u0068u002fu0071u007au002fu0078u0061u0066u002fu0073u0065u0072u0076u0069u0063u0065u002fu0049u0058u0041u0046u0053u0065u0072u0076u0069u0063u0065u003b' => "Lnet/slwish/qz/xaf/service/IXAFService;"

    问题:这里都是1个字节表示,那2个字节或者3个字节是怎么表示的呢?
    猜测,如果不是1个字节,那就去javac编译时指定的编码,如果是utf-8,那就存储3个字节(取3个字节)
    javac -encoding utf-8 Demo.java

    要想看详细的常量池等其他信息,可以用javap -verbose Demo.class查看。

    访问标志

    access_flags

    访问标志表

    下次列出...

    例子

    接口类型

    public abstract class B {
    	// 代码省略...
    }
    

    编译后的文件就有这几种标志

    ACC_PUBLIC, ACC_SUPER, ACC_ABSTRACT

    那么,他的access_flags就为0x0001|0x0020|0x0400=0x0421

    枚举类型

    public enum A {
    	// 代码省略...
    }
    

    编译后的文件就有这几种标志

    ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM

    那么,他的access_flags就为0x0001|0x0010|0x0020|0x4000=0x4031

    类索引、父类索引与接口索引集合

    名称 类型
    类索引(this_class) u2
    父类索引(super_class) u2
    接口索引集合(interfaces) [u2, u2, ...]

    最近更新时间20200131

  • 相关阅读:
    C# 时间格式化
    下载好证书后,手机无法安装fiddler证书
    charles抓包步骤整理
    Windows 8的本地化应用程序清单
    代码滑动panorama-即程序中设置SelectedIndex
    WP7开发 Sqlite数据库的使用 解决Unable open the database
    mybatis plus eq and or
    弹出窗口
    父子窗口传递参数
    从后台数据库查询的List数据怎么在前台combobox显示
  • 原文地址:https://www.cnblogs.com/jarjune/p/12247326.html
Copyright © 2011-2022 走看看