网站首页 > 技术文章 正文
Windows 操作系统上编译的 Java 程序,不经过修改就能够直接在 Linux 操作系统上运行;与之对比的是 C 语言,在 Linux 平台编译的 C 程序,一般情况下如果不进行特殊的转换,那么是不能在 Windows 操作系统上运行的。
要了解 Java 是如何实现这一目标的,我们需要对 Java实际的运行做一个简单的介绍。首先 Java 的源程序的扩展名是.java,经过编译程序编译之后生成扩展为.class 的字节码文件。
本文分析class文件的格式,描述 Java 如何执行字节码,并通过 ASM 工具动态生成属性访问工具类,它类似 ReflectASM,是一个高性能反射处理工具。
一、基础知识:
在.class 文件中,类名使用的都是全限定名,并且其表示方式与源文件中的方式不一致,比如 java.lang.String 在 String.class 中的表示方式就是 java/lang/String。
Java 虚拟机的操作基于两种数据类型:基本类型和引用类型。
1.基本类型:包括数字类型、boolean 类型和 returnAddress,其中 returnAddress 在 Java 语言中没有对应类型。
2.引用类型:包括 class、array、interface,引用类型是与实例关联的。这些类型在.class 文件中有不同的描述,如下表所示。
引用类型举例,如下表所示。
方法的描述是参数类型描述与返回类型描述的组合,参数类型描述在一对()之间,后边紧跟返回类型的描述。我们以 java.lang.Object 与 java.lang.String 中的几个方法举例,如下表所示。
二、.class文件的格式
.class 文件的格式(类似 C 语言)如下:
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
classFile 是二进制字节流,以 8 位二进制数据为基础构成,虽然可以区分一个个数据项,但其结构是按顺序线性排列的,各个数据项中间没有其他的分隔符。
在 class 文件的结构中,只有两种数据类型:无符号数和表。其中 u1、u2、u4 分别代表无符号 1 个字节、2 个字节、4 个字节,而且其多字节的排列是“大端法”,即高位字节在低位。 “表”是由多个无符号数或其他表项构成的,比如 cp_info 表示的就是常量池表。
1.Magic:魔数,4 个字节,固定为 0xCAFEBABE。
2.minor_version、major_version:分别占 2 个字节,表示子版本号和主版本号,用于 Java 虚拟机识别是否支持该.class 文件,以及是否支持新特性等。
3.constant_pool_count:2 个字节,其表示的值为常量池的实际大小+1。
4.constant_pool[]:常量池,其中包含各种格式的常量,包括类的全限定名、字段名称和描述符、方法名称和描述符等,其通用格式为 cp_info{u1 tag;u1 info[]},由于篇幅有限,不再详细展开介绍常量池结构。我们知道 Java 类的所有常量、类名、方法名等字符串都存放在常量池中。
5.access_flags:2 个字节,表示该类或接口的访问标志,比如 ACC_PUBLIC(值为 0x0001)表示 public,ACC_FINAL 表示 final(值为 0x0010),因此 0x0011 表示 final public。
6.this_class:2 个字节,表示当前类,其值为常量池中的索引,该位置所表示的常量类型必须为 0x07,即 class 类型。
7.super_class:2 个字节,表示当前类的直接父类,其值为常量池中的索引。该位置所表示的常量类型必须为 0x07,即 class 类型,当然在 Object 类的.class 文件中,该值为 0x0000。
8.interfaces_count:2 个字节,表示当前类或接口直接实现的接口的数量。
9.interfaces[]:表示直接实现的接口,其值为常量池中索引的位置,且类型必须为 0x07。
10.interfaces_count:2 个字节,表示当前类或接口直接实现的接口的数量。
11.interfaces[]:表示直接实现的接口,其值为常量池中索引的位置,且类型必须为 0x07。
12.methods_count:2 个字节,表示该类的方法表中方法结构的数量。
13.methods[]:方法表,表示该类中的所有方法,包括实例方法、类方法、初始化方法等,不包括从父类或父接口中继承但没实现的方法。
14.attributes_count:2 个字节,表示该.class 文件的属性表中实体的数量。
15.attributes[]:属性表,此位置的属性表示的是.class 文件中的属性,存储在此位置的属性是有限值的。
字段的结构如下:
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
方法的结构如下:
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
属性的结构如下:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
我们看到 Class、Filed、Method,甚至在 Attribute 中都有属性结构,但不同的位置拥有的属性是不同的,比如 SourceFile 属性存储在 ClassFile 中,Code 属性存储在 Method 结构中,而存储字节码对应 Java 源码行号的 LineNumberTable 和描述本地变量表中变量与 Java 源码变量对应关系的 LocalVariableTable 属性则存储在 Code 属性中,用于 Java Debug。
内容摘自《高性能Java系统权威指南》第九章
本书特点:
内容上,总结作者从事Java开发20年来在头部IT企业的高并发系统经历的真实案例,极具参考意义和可读性。
对于程序员和架构师而言,Java 系统的性能优化是一个超常规的挑战。这是因为 Java 语言和 Java 运行平台,以及 Java 生态的复杂性决定了 Java 系统的性能优化不再是简单的升级配置或者简单的 “空间换时间”的技术实现,这涉及 Java 的各种知识点。
本书从高性能、易维护、代码增强以及在微服务系统中编写Java代码的角度来描述如何实现高性能Java系统,结合真实案例,让读者能够快速上手实战。
风格上,本书的风格偏实战,读者可以下载书中的示例代码并运行测试。读者可以从任意一章开始阅读,掌握性能优化知识为公司的系统所用。
本书适合:
中高级程序员和架构师;
以及有志从事基础技术研发、开源工具研发的极客阅读;
也可以作为 Java 笔试和面试的参考书。
- 上一篇: Java 反编译工具的使用与对比分析
- 下一篇: Java—类加载的基本机制和过程
猜你喜欢
- 2025-01-03 Java 关键字之 native 详解
- 2025-01-03 三石说:java中常用的几个类
- 2025-01-03 反射、枚举以及Lambda表达式
- 2025-01-03 Java 新手教程,建议收藏
- 2025-01-03 Java零基础入门,科普Java你应该了解什么
- 2025-01-03 Java 代码执行原理
- 2025-01-03 揭秘双亲委派模型:Java类加载的“幕后英雄”
- 2025-01-03 你知道 Java 中关键字 enum 是一个语法糖吗?反编译枚举类
- 2025-01-03 Java中的枚举,这一篇全了,一些不为人知的干货
- 2025-01-03 Java反编译工具
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)