(3) 深入理解Java Class文件格式(二)

好文转载:http://blog.csdn.net/zhangjg_blog/article/details/21487287

在上一篇文章 深入理解Java Class文件格式(一) 中, 介绍了class文件在整个Java体系结构中的位置和作用, 并对class文件的整体格式做了说明, 介绍了其中的魔数和版本号的相关内容, 并对常量池做了概述。 在本文章, 继续介绍class文件中的其他内容。

class文件中的特殊字符串

首先说明一下, 所谓的特殊字符串出现在class文件中的常量池中, 所以在上一篇博客中, 只是对常量池介绍了一个大概。 本着循序渐进和减少跨度的原则, 首先把class文件中的特殊字符串做一个详细的介绍, 然后再回过头来继续讲解常量池。

在上文中, 我们提到特殊字符串是常量池中符号引用的一部分, 至于符号引用的概念, 会在以后提到。 现在我们将重点放在特殊字符串上。 特殊字符串包括三种: 类的全限定名, 字段和方法的描述符, 特殊方法的方法名。 下面我们就分别介绍这三种特殊字符串。

(1) 类的全限定名

在常量池中, 一个类型的名字并不是我们在源文件中看到的那样, 也不是我们在源文件中使用的包名加类名的形式。 源文件中的全限定名和class文件中的全限定名不是相同的概念。 源文件中的全新定名是包名加类名, 包名的各个部分之间,包名和类名之间, 使用点号分割。 如Object类, 在源文件中的全限定名是java.lang.Object 。 而class文件中的全限定名是将点号替换成“/” 。 例如, Object类在class文件中的全限定名是 java/lang/Object 。 如果读者之前没有接触过class文件格式, 是class文件格式的初学者, 在这里不必知道全限定名在class文件中是如何使用的, 只需要知道, 源文件中一个类的名字, 在class文件中是用全限定名表述的。

(2) 描述符

我们知道在一个类中可以有若干字段和方法, 这些字段和方法在源文件中如何表述, 我们再熟悉不过了。 既然现在我们要学习class文件格式, 那么我们就要问, 一个字段或一个方法在class文件中是如何表述的? 在本文中, 我们会讨论方法和字段在class文件中的描述。 方法和字段的描述符并不会把方法和字段的所有信息全都描述出来, 毕竟描述符只是一个简单的字符串。

在讲解描述符之前, 要先说明一个问题, 那就是所有的类型在描述符中都有对应的字符或字符串来对应。 比如, 每种基本数据类型都有一个大写字母做对应, void也有一个大写字符做对应。 下表是void和基本数据类型在描述符中的对应。

基本数据类型和void类型 类型的对应字符
byte B
char C
double D
float F
int I
long J
short S
boolean Z
void V

基本上都是以类型的首字符变成大写来对应的, 其中long和boolean是特例, long类型在描述符中的对应字符是J, boolean类型在描述符中的对应字符是Z 。

基本类型和void在描述符中都有一个大写字符和他们对应, 那么引用类型(类和接口,枚举)在描述符中是如何对应的呢? 引用类型的对应字符串(注意, 引用类型在描述符中使用一个字符串做对应) , 这个字符串的格式是:

  1. “L” + 类型的全限定名 + “;”

注意,这三个部分之间没有空格, 是紧密排列的。 如Object在描述符中的对应字符串是: Ljava/lang/Object;  ; ArrayList在描述符中的对应字符串是: Ljava/lang/ArrayList;  ; 自定义类型com.example.Person在描述符中的对应字符串是: Lcom/example/Person; 。

我们知道, 在Java语言中数组也是一种类型, 一个数组的元素类型和他的维度决定了他的类型。 比如, 在 int[] a 声明中, 变量a的类型是int[] , 在 int[][] b 声明中, 变量b的类型是int[][] , 在 Object[] c 声明中, 变量c的类型是Object[] 。既然数组是类型, 那么在描述符中, 也应该有数组类型的对应字符串。 在class文件的描述符中, 数组的类型中每个维度都用一个 [ 代表, 数组类型整个类型的对应字符串的格式如下:

  1. 若干个“[”  +  数组中元素类型的对应字符串

下面举例来说名。 int[]类型的对应字符串是: [I  。 int[][]类型的对应字符串是: [[I 。 Object[]类型的对应字符串是: [Ljava/lang/Object; 。 Object[][][]类型的对应字符串是: [[[Ljava/lang/Object; 。

介绍完每种类型在描述符中的对应字符串, 下面就开始讲解字段和方法的描述符。

字段的描述符就是字段的类型所对应的字符或字符串。 如: int i 中, 字段i的描述符就是 I 。 Object o中, 字段o的描述符就是 Ljava/lang/Object;  。 double[][] d中, 字段d的描述符就是 [[D 。

方法的描述符比较复杂, 包括所有参数的类型列表和方法返回值。 它的格式是这样的:

  1. (参数1类型 参数2类型 参数3类型 ...)返回值类型

其中, 不管是参数的类型还是返回值类型, 都是使用对应字符和对应字符串来表示的, 并且参数列表使用小括号括起来, 并且各个参数类型之间没有空格, 参数列表和返回值类型之间也没有空格。

下面举例说明(此表格来源于《深入Java虚拟机》)。

方法描述符 方法声明
()I int getSize()
()Ljava/lang/String; String toString()
([Ljava/lang/String;)V void main(String[] args)
()V void wait()
(JI)V void wait(long timeout, int nanos)
(ZILjava/lang/String;II)Z boolean regionMatches(boolean ignoreCase, int toOffset, String other, int ooffset, int len)
([BII)I int read(byte[] b, int off, int len )
()[[Ljava/lang/Object; Object[][] getObjectArray()

(3) 特殊方法的方法名

首先要明确一下, 这里的特殊方法是指的类的构造方法和类型初始化方法。 构造方法就不用多说了, 至于类型的初始化方法, 对应到源码中就是静态初始化块。 也就是说, 静态初始化块, 在class文件中是以一个方法表述的, 这个方法同样有方法描述符和方法名。

类的构造方法的方法名使用字符串 <init> 表示, 而静态初始化方法的方法名使用字符串 <clinit> 表示。 除了这两种特殊的方法外, 其他普通方法的方法名, 和源文件中的方法名相同。

总结

到此为止, 关于特殊字符串就讲解完了。 最后做一下总结:

class文件中的特殊字符串包括类(包括接口, 枚举)的全限定名, 字段的描述符和方法的描述符。 其中类的全限定名比较简单易于理解, 字段和方法的描述符由于涉及到每种类型的映射, 可能稍显复杂。 要理解描述符, 主要是要熟记每种类型(包括8种基本数据类型,类类型, 数组类型和void)在描述符中所对应的描述字符或字符串。

还有一点需要注意, 就是方法和字段的描述符中, 不包括字段名和方法名, 字段描述符中只包括字段类型, 方法描述符中只包括参数列表和返回值类型。

时间: 2024-12-05 19:13:01

(3) 深入理解Java Class文件格式(二)的相关文章

(3) 深入理解Java Class文件格式(三)

转载:http://blog.csdn.net/zhangjg_blog/article/details/21557357 首先, 让我们回顾一下关于class文件格式的之前两篇博客的主要内容. 在 深入理解Java Class文件格式(一) 中, 讲解了class文件在整个java体系结构中的位置和作用, 讲解了class文件中的魔数和版本号相关的信息, 并且对常量池进行了概述. 在 深入理解Java Class文件格式(二) 中, 主要讲解了class文件中的特殊字符串, 包括类的全限定名,

(5) 深入理解Java Class文件格式(五)

前情回顾 本专栏的前几篇博文, 对class文件中的常量池进行了详细的解释. 前文讲解了常量池中的7种数据项, 它们分别是: CONSTANT_Utf8_info CONSTANT_NameAndType_info CONSTANT_Integer_info CONSTANT_Float_info CONSTANT_Long_info CONSTANT_Double_info CONSTANT_String_info 关于这七种数据项, 前面的文章已经讲得很详细了, 不了解的同学请先参阅前面的博

(7) 深入理解Java Class文件格式(七)

转载:http://blog.csdn.net/zhangjg_blog/article/details/22091529 本专栏列前面的一系列博客, 对Class文件中的一部分数据项进行了介绍. 本文将会继续介绍class文件中未讲解的信息. 先回顾一下上面一篇文章. 在上一篇博客中, 我们介绍了: this_class    对当前类的描述 super_class    对当前类的超类的描述 interfaces_count    当前类直接实现的接口的数量或当前接口直接继承的接口的数量 i

深入理解java虚拟机(二)HotSpot Java对象创建,内存布局以及访问方式

内存中对象的创建.对象的结构以及访问方式. 一.对象的创建 在语言层面上,对象的创建只不过是一个new关键字而已,那么在虚拟机中又是一个怎样的过程呢? (一)判断类是否加载.虚拟机遇到一条new指令的时候,首先会检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号代表的类是否被加载.解析并初始化.如果没有完成这个过程,则必须执行相应类的加载. (二)在堆上为对象分配空间.对象需要的空间大小在类加载完成后便能确定.之后便是在堆上为该对象分配固定大小的空间.分配的方式也有两种:

(4) 深入理解Java Class文件格式(四)

转载:http://blog.csdn.net/zhangjg_blog/article/details/21658415 前情回顾 在上一篇博客深入理解Java Class文件格式(三) 中, 介绍了常量池中的两种类型的数据项, 分别是 CONSTANT_Utf8_info CONSTANT_NameAndType_info . CONSTANT_Utf8_info中存储了几乎所有类型的字符串, 包括方法名, 字段名, 描述符等等. 而CONSTANT_NameAndType_info是方法符

(2) 深入理解Java class文件格式(一)

好文转载:http://blog.csdn.net/zhangjg_blog/article/details/21486985 Class文件在Java体系结构中的位置和作用 在上一篇博客中, 大致讲解了Java虚拟机的体系结构和执行原理. 本篇博客主要讲解能够被JVM识别, 加载并执行的class文件的格式. 对于理解JVM和深入理解Java语言, 学习并了解class文件的格式都是必须要掌握的功课. 原因很简单, JVM不会理解我们写的Java源文件, 我们必须把Java源文件编译成clas

深入理解JAVA集合系列二:ConcurrentHashMap源码解读

HashMap和Hashtable的区别 在正式开始这篇文章的主题之前,我们先来比较下HashMap和Hashtable之间的差异点: 1.Hashtable是线程安全的,它对外提供的所有方法都是都使用了synchronized,是同步的,而HashMap是非线程安全的. 2.Hashtable不允许value为空,否则会抛出空指针异常: 而HashMap中key.value都可以为空. 1 public synchronized V put(K key, V value) { 2 // Mak

深入理解java虚拟机笔记(二)-垃圾回收

ps:文中的图片都来自网络.部分图片来源 1. 前言 作为一种高级语言,比起c和c++来,很进步的一点就是垃圾回收机制.这省去来了我们很多的工作,不过,我们仍然需要了解垃圾回收,这对我们的成长很有帮助. 2. 引用计数法 引用计数法在很多高级语言都有,如python,java也不例外.对象内部维护有一个被其他对象引用的引用计数,当这个引用计数为0的时候,表示对象可以被回收. 引用计数法存在一个问题,就是循环引用,加入a引用b,b同时也引用a,那么就存在ab的引用计数都不为0的情况. 3. 可达性

深入理解java虚拟机(二):java内存溢出实战

按照java内存的结构,发生内存溢出的地方常在于堆.栈.方法区.直接内存. 1.堆溢出 堆溢出原因莫过于对象太多导致,看代码. package baby.oom;     import java.util.ArrayList;   import java.util.List;     /**   * java 堆溢出   * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError   * @author   */   public clas