服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java class文件格式之方法_动力节点Java学院整理

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

2020-11-17 11:05zhangjg Java教程

这篇文章主要为大家详细介绍了Java class文件格式之方法的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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的结构如下:

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

(1)access_flags

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

Java class文件格式之方法_动力节点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。 这些属性会在后面的文章中进行介绍。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.bjpowernode.test;
 
 
public class programer extends person{
 
 
 
 private computer computer;
 
 public programer(computer computer){
  this.computer = computer;
 }
 
public void dowork(){
  computer.calculate();
 }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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选项, 否则的话, 虽然常量池中有字段引用信息, 但是不会输出字段信息, 即下面这两行不会输出:

?
1
2
private com.bjpowernode.test.computer computer;
flags: acc_private

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

?
1
2
javap -c -v -private -
classpath . com.bjpowernode.test.programer

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

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

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的结构是一样的:

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

(1)access_flags

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

Java class文件格式之方法_动力节点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的结构, 下面我们以代码来说明, 还是使用上面的源码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.jg.zhang;
 
public class programer extends person{
 
  
 private computer computer;
  
 public programer(computer computer){
  this.computer = computer;
 }
  
 public void dowork(){
  computer.calculate();
 }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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是如何引用常量池中的数据项来描述当前类中定义的方法的。 图中虚线范围内表示常量池所在的区域:

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

总结

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

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

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

延伸 · 阅读

精彩推荐