Java class文件格式之方法_动力节点Java学院整理

class文件中的fields_count和fields

fields_count描述的是当前的类中定义的字段的个数, 注意, 这里包括静态字段, 但不包括从父类继承的字段。 如果当前class文件是由一个接口生成的, 那么这里的fields_count描述的是接口中定义的字段, 我们知道, 接口中定义的字段默认都是静态的。此外要说明的是, 编译器可能会自动生成字段, 也就是说, class文件中的字段的数量可能多于源文件中定义的字段的数量。 举例来说, 编译器会为内部类增加一个字段, 这个字段是指向外围类的对象的引用。

位于fields_count下面的数据叫做fields, 可以把它看做一个数组, 数组中的每一项是一个field_info 。这个数组中一共有fields_count个field_info , 每个field_info都是对一个字段的描述。 下面我们详细讲解field_info的结构。 每个field_info的结构如下:

(1)access_flags

其中access_flags占两个字节, 描述的是字段的访问标志信息。 这里就不在详细介绍了, 下面给出一张表格(该表格来自《深入Java虚拟机》):

(2)name_index

access_flags下面的两个字节是name_index, 这是一个指向常量池的索引, 它描述的是当前字段的字段名。 这个索引指向常量池中的一个CONSTANT_Utf8_info数据项。 这个CONSTANT_Utf8_info数据项中存放的字符串就是当前字段的字段名。

(3)descriptor_index

name_index下面的两个字节叫做descriptor_index , 它同样是一个指向常量池的索引, 它描述的是当前字段的描述符。 这个索引指向常量池中的一个CONSTANT_Utf8_info数据项。 这个CONSTANT_Utf8_info数据项中存放的字符串就是当前字段的描述符。

(4)attributes_count和attributes

descriptor_index 下面是attributes_count和attributes 。 这是对当前字段所具有的属性的描述。 这里的属性和源文件中的属性不是同一个概念, 在源文件测层面中, 属性是字段的另一种叫法, 希望读者不要疑惑。读者也不要轻视class文件中的属性, 这些属性可以描述很多的信息。 我们会在后面的文章中进行介绍。

attributes_count表示这个字段有几个属性。attributes 可以看成一个数组, 数组中的每一项都是一个attribute_info , 每个attribute_info 表示一个属性, 数组中一共有attributes_count个属性。可以出现在filed_info中的属性有三种, 分别是ConstantValue, Deprecated, 和 Synthetic。 这些属性会在后面的文章中进行介绍。

下面我们以代码的形式进行解释, 源码如下:

package com.bjpowernode.test; 

public class Programer extends Person{ 

 private Computer computer; 

 public Programer(Computer computer){
  this.computer = computer;
 } 

public void doWork(){
  computer.calculate();
 }
}

反编译之后, 常量池中会有如下信息(这里省略了大部分无关信息):

Constant pool: 

.........
......... 

 #5 = Utf8    computer
 #6 = Utf8    Lcom/jg/zhang/Computer; 

.........
......... 

{ 

 private com.jg.zhang.Computer computer;
 flags: ACC_PRIVATE 

.........
......... 

} 

从反编译的结果可以看出, 源文件中定义了一个Computer类型的字段computer, 并且是private的。 然后常量池中有这个字段的字段名和描述符。 其中常量池第五项的CONSTANT_Utf8_info是字段名, 第六项的CONSTANT_Utf8_info是该字段的描述符。这里有一点需要说明, 在反编译Programer.class时,由于computer是私有的, 要加- private选项, 否则的话, 虽然常量池中有字段引用信息, 但是不会输出字段信息, 即下面这两行不会输出:

private com.bjpowernode.test.Computer computer;
flags: ACC_PRIVATE

如果在javap中加入 - private选项, 那么就会有上面两行的输出。 使用的命令如下:

javap -c -v -private -
classpath . com.bjpowernode.test.Programer

根据反编译的结果,可以下面给出示意图, 该图说明了与computer相对应的field_info是不合引用常量池的 ( 其中虚线范围内表示常量池):

class文件中的methods_count和methods

fields下面的信息是methods_count和methods 。 methods_count描述的是当前的类中定义的方法的个数, 注意, 这里包括静态方法, 但不包括从父类继承的方法。 如果当前class文件是由一个接口生成的, 那么这里的methods_count描述的是接口中定义的抽象方法的数量, 我们知道, 接口中定义的方法默认都是公有的。此外需要说明的是, 编译器可能会在编译时向class文件增加额外的方法, 也就是说, class文件中的方法的数量可能多于源文件中由用户定义的方法。 举例来说: 如果当前类没有定义构造方法, 那么编译器会增加一个无参数的构造函数<init>; 如果当前类或接口中定义了静态变量, 并且使用初始化表达式为其赋值, 或者定义了static静态代码块, 那么编译器在编译的时候会默认增加一个静态初始化方法<clinit> 。

位于methods_count下面的数据叫做methods , 可以把它看做一个数组, 数组中的每一项是一个method_info 。这个数组中一共有methods_count个method_info , 每个method_info 都是对一个方法的描述。 下面我们详细讲解method_info 的结构。 每个method_info 的结构如下, 几乎和field_info的结构是一样的:

(1)access_flags

其中access_flags占两个字节, 描述的是方法的访问标志信息。 这里就不在详细介绍了, 下面给出一张表格(该表格来自《深入Java虚拟机》):

(2)name_index

access_flags下面的两个字节是name_index, 这是一个指向常量池的索引, 它描述的是当前方法的方法名。 这个索引指向常量池中的一个CONSTANT_Utf8_info数据项。 这个CONSTANT_Utf8_info数据项中存放的字符串就是当前方法的方法名。

(3)descriptor_index

name_index下面的两个字节叫做descriptor_index , 它同样是一个指向常量池的索引, 它描述的是当前方法的描述符。 这个索引指向常量池中的一个CONSTANT_Utf8_info数据项。 这个CONSTANT_Utf8_info数据项中存放的字符串就是当前方法的描述符。

(4)attributes_count和attributes

descriptor_index 下面是attributes_count和attributes 。 这是对当前方法所具有的属性的描述。 这里的属性和源文件中的属性不是同一个概念, 在源文件测层面中, 属性是字段的另一种叫法, 希望读者不要疑惑。读者也不要轻视class文件中的属性, 这些属性可以描述很多的信息。 我们会在后面的文章中进行介绍。

attributes_count表示这个字段有几个属性。attributes 可以看成一个数组, 数组中的每一项都是一个attribute_info , 每个attribute_info 表示一个属性, 数组中一共有attributes_count个属性。可以出现在method_info 中的属性有三种, 分别是Code, Deprecated, Exceptions 和Synthetic。 在这几个属性中, 尤其是Code和Exceptions 非常重要, 这两个属性对于在class文件中完整描述一个方法起着至关重要的作用, 其中Code属性中存放方法的字节面指令,Exceptions 属性是对方法声明中抛出的异常的描述 。 这两属性以及其他一些属性, 会在下一篇文章中详细介绍, 敬请关注。

介绍完了每个method_info的结构, 下面我们以代码来说明, 还是使用上面的源码:

package com.jg.zhang; 

public class Programer extends Person{ 

 private Computer computer; 

 public Programer(Computer computer){
  this.computer = computer;
 } 

 public void doWork(){
  computer.calculate();
 }
}

反编译之后, 常量池中会有如下信息(这里省略了大部分无关信息):

Constant pool: 

......... 

 #7 = Utf8    <init>
 #8 = Utf8    (Lcom/jg/zhang/Computer;)V 

......... 

 #12 = Utf8    ()V 

......... 

 #19 = Utf8    doWork 

{ 

......... 

 public com.jg.zhang.Programer(com.jg.zhang.Computer);
 flags: ACC_PUBLIC 

......... 

 public void doWork();
 flags: ACC_PUBLIC 

.........
} 

由反编译结果可以看出, 该类中定义了两个方法, 其中一个是构造方法, 一个是doWork方法, 且这两个方法都是public的。 这两个方法的描述信息都存放在常量池。 其中第7项的CONSTANT_Utf8_info为构造方法的方法名, 第8项的CONSTANT_Utf8_info为构造方法的方法描述符, 第19项的CONSTANT_Utf8_info为doWork方法的方法名, 第12项的CONSTANT_Utf8_info为doWork方法的方法描述符。

根据常量池中的信息, 可以得出如下的示意图, 该示意图形象的说明了class文件中的method_info是如何引用常量池中的数据项来描述当前类中定义的方法的。 图中虚线范围内表示常量池所在的区域:

总结

到此为止, 我们就介绍完了class文件中的fields和methods, 进行一下总结。 
 fields是对当前类中定义的字段的描述, 其中每个字段使用一个field_info表示, fields中有fields_count个field_info。
methods是对当前类或者接口中声明的方法的描述, 其中每个方法使用一个method_info表示, methods中有methods_count个method_info。

在下一篇博客中, 将会介绍class文件中的各个属性, 敬请关注。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java class文件格式之属性_动力节点Java学院整理

    class文件中的attributes_count和attributes attributes_count位于class文件中methods的下面. 它占两个字节, 存储的是一个整数值, 表示class文件中属性的个数.  attributes_count下面的是attributes, 可以把它看做一个数组, 每个数组项是一个attribute_info , 每个attribute_info 表示一个属性.attributes中有 attributes_count个attribute_info

  • Java class文件格式之特殊字符串_动力节点Java学院整理

    class文件中的特殊字符串 首先说明一下, 所谓的特殊字符串出现在class文件中的常量池中,本着循序渐进和减少跨度的原则, 首先把class文件中的特殊字符串做一个详细的介绍, 然后再回过头来继续讲解常量池. 现在我们将重点放在特殊字符串上. 特殊字符串包括三种: 类的全限定名, 字段和方法的描述符, 特殊方法的方法名. 下面我们就分别介绍这三种特殊字符串. (1) 类的全限定名 在常量池中, 一个类型的名字并不是我们在源文件中看到的那样, 也不是我们在源文件中使用的包名加类名的形式. 源文

  • 深入理解Java class文件格式_动力节点Java学院整理

    Class文件在Java体系结构中的位置和作用 对于理解JVM和深入理解Java语言, 学习并了解class文件的格式都是必须要掌握的功课. 原因很简单, JVM不会理解我们写的Java源文件, 我们必须把Java源文件编译成class文件, 才能被JVM识别, 对于JVM而言, class文件相当于一个接口, 理解了这个接口, 能帮助我们更好的理解JVM的行为:另一方面, class文件以另一种方式重新描述了我们在源文件中要表达的意思, 理解class文件如何重新描述我们编写的源文件, 对于深

  • Java class文件格式之属性详解_动力节点java学院整理

    Code属性 code属性是方法的一个最重要的属性. 因为它里面存放的是方法的字节码指令, 除此之外还存放了和操作数栈,局部变量相关的信息. 所有不是抽象的方法, 都必须在method_info中的attributes中有一个Code属性.下面是Code属性的结构, 为了更直观的展示Code属性和method_info的包含关系, 特意画出了method_info: 下面依次介绍code属性中的各个部分. attribute_name_index指向常量池中的一个CONSTANT_Utf8_in

  • Java class文件格式之数据类型_动力节点Java学院整理

    CONSTANT_Integer_info 一个常量池中的CONSTANT_Integer_info数据项, 可以看做是CONSTANT_Integer类型的一个实例. 它存储的是源文件中出现的int型数据的值. 同样, 作为常量池中的一种数据类型, 它的第一个字节也是一个tag值, 它的tag值为3, 也就是说, 当虚拟机读到一个tag值为3的数据项时, 就知道这个数据项是一个CONSTANT_Integer_info, 它存储的是int型数值的值. 紧挨着tag的下面4个字节叫做bytes,

  • Java class文件格式之访问标志信息_动力节点Java学院整理

    class文件中的访问标志信息 位于常量池下面的2个字节是access_flags . access_flags 描述的是当前类(或者接口)的访问修饰符, 如public, private等, 此外, 这里面还存在一个标志位, 标志当前的额这个class描述的是类, 还是接口.access_flags 的信息比较简单, 下面列出access_flags 中的各个标志位的信息.本来写这个系列博客参考的是<深入java虚拟机>, 但是这本书比较老了, 关于java 5以后的新特性没有进行解释,这本

  • Java class文件格式总结_动力节点Java学院整理

    我们都知道JVM能够识别的只有class格式的文件, 而源文件只是我们人能识别的, 不能被JVM识别. 那我们要在更深的层次上理解Java语言, 理解JVM, 只懂源文件是不够的, 因为虚拟机的很多的行为, 是在class文件中定义的, 而我们要理解JVM的行为, 就必须也学会JVM能理解的"语言", 那就是class文件格式 . 就像我们想要深入的了解一个外国人, 只站在自己的角度上是不可能了解他的, 只有你学会了他的语言, 才能对他更了解, 因为只有你理解了他说的话, 才能知道他做

  • Java class文件格式之常量池_动力节点Java学院整理

    常量池中各数据项类型详解 常量池中的数据项是通过索引来引用的, 常量池中的各个数据项之间也会相互引用.在这11中常量池数据项类型中, 有两种比较基础, 之所以说它们基础, 是因为这两种类型的数据项会被其他类型的数据项引用. 这两种数据类型就是CONSTANT_Utf8 和 CONSTANT_NameAndType , 其中CONSTANT_NameAndType类型的数据项(CONSTANT_NameAndType_info)也会引用CONSTANT_Utf8类型的数据项(CONSTANT_Ut

  • Java class文件格式之数据类型(二)_动力节点Java学院整理

    常量池中各数据项类型详解(续) (8) CONSTANT_Class_info 常量池中的一个CONSTANT_Class_info, 可以看做是CONSTANT_Class数据类型的一个实例. 他是对类或者接口的符号引用. 它描述的可以是当前类型的信息, 也可以描述对当前类的引用, 还可以描述对其他类的引用. 也就是说, 如果访问了一个类字段, 或者调用了一个类的方法, 对这些字段或方法的符号引用, 必须包含它们所在的类型的信息, CONSTANT_Class_info就是对字段或方法符号引用

  • Java class文件格式之方法_动力节点Java学院整理

    class文件中的fields_count和fields fields_count描述的是当前的类中定义的字段的个数, 注意, 这里包括静态字段, 但不包括从父类继承的字段. 如果当前class文件是由一个接口生成的, 那么这里的fields_count描述的是接口中定义的字段, 我们知道, 接口中定义的字段默认都是静态的.此外要说明的是, 编译器可能会自动生成字段, 也就是说, class文件中的字段的数量可能多于源文件中定义的字段的数量. 举例来说, 编译器会为内部类增加一个字段, 这个字段

  • Java中json使用方法_动力节点Java学院整理

    摘要:JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C.C++.C#.Java.JavaScript.Perl.Python等).这些特性使JSON成为理想的数据交换语言. 易于人阅读和编写,同时也易于机器解析和生成(网络传输速率). 一.准备工作  json是个非常重要的数据结构,在web开发中应用十分广泛.我觉得每个人都应该好好

  • Java设计模式之备忘录模式_动力节点Java学院

    定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样就可以将该对象恢复到原先保存的状态 类型:行为类 类图: 我们在编程的时候,经常需要保存对象的中间状态,当需要的时候,可以恢复到这个状态.比如,我们使用Eclipse进行编程时,假如编写失误(例如不小心误删除了几行代码),我们希望返回删除前的状态,便可以使用Ctrl+Z来进行返回.这时我们便可以使用备忘录模式来实现. 备忘录模式的结构 发起人:记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和

  • 深入理解Java中的final关键字_动力节点Java学院整理

    Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使用final关键字的实例.final经常和static一起使用来声明常量,你也会看到final是如何改善应用性能的. final关键字的含义? final在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量.一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如

  • Java Date类常用示例_动力节点Java学院整理

    Date类 在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和日期处理.这里简单介绍一下Date类的使用. 1.使用Date类代表当前系统时间 Date d = new Date(); System.out.println(d); 使用Date类的默认构造方法创建出的对象就代表当前时间,由于Date类覆盖了toString方法,所以可以直接输出Date类型的对象,显示的结果如下: Sun Ma

  • Java设计模式之迭代器模式_动力节点Java学院整理

    定义:提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节. 类型:行为类模式 类图: 如果要问Java中使用最多的一种模式,答案不是单例模式,也不是工厂模式,更不是策略模式,而是迭代器模式,先来看一段代码吧: public static void print(Collection coll){ Iterator it = coll.iterator(); while(it.hasNext()){ String str = (String)it.next(); System.out

  • Java System类详解_动力节点Java学院整理

    System类是jdk提供的一个工具类,有final修饰,不可继承,由名字可以看出来,其中的操作多数和系统相关.其功能主要如下: • 标准输入输出,如out.in.err • 外部定义的属性和环境变量的访问,如getenv()/setenv()和getProperties()/setProperties() • 加载文件和类库的方法,如load()和loadLibrary(). • 一个快速拷贝数组的方法:arraycopy() • 一些jvm操作,如gc().runFinalization()

  • Java Runtime类详解_动力节点Java学院整理

    一.概述 Runtime类封装了运行时的环境.每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接.一般不能实例化一个Runtime对象,应用程序也不能创建自己的 Runtime 类实例,但可以通过 getRuntime 方法获取当前Runtime运行时对象的引用.一旦得到了一个当前的Runtime对象的引用,就可以调用Runtime对象的方法去控制Java虚拟机的状态和行为. 当不被信任的代码调用任何Runtime方法时,常常会引起SecurityExc

随机推荐