【JVM虚拟机】(7)---深入理解Class中-属性集合

#【JVM虚拟机】(7)---深入理解Class中-属性集合

之前有关class文件已经写了两篇博客:

1、【JVM虚拟机】(5)---深入理解JVM-Class中常量池

2、【JVM虚拟机】(6)---深入理解Class中访问标志、类索引、父类索引、接口索引

那么这篇博客主要讲有关 字段表集合 相关的理解和代码示例。

字段表:用于描述接口或者类中声明的变量,字段包括类级(static修饰)变量以及实例级变量,但是不包括局部变量(方法内部变量)。

一、概念

字段表集合:包括了字段计数器字段数据区如图:

Field_info: 依次包含访问标志(access_flags)、名称索引(name_index)、描述符索引(descriptor_index)、属性表集合(attributes)几项。

字段修饰符放在access_flags项目中,它与类中的access_flags项目是非常相似的,都是一个u2的数据类型.

(

跟随access_flags标志的是两项索引值:name_indexdescriptor_index,它们都是对常量池的引用,分别代表着字段的简单名称以及字段方法和方法的描述符

描述符的作用:是用来描述字段的数据类型,方法的参数列表(包括数量,类型以及顺序)和返回值。

描述符规则: 基本数据类型以及代表无返回值的void类型都用一个大写字符来表示,而对象类型则用字符加L加对象名的全限定名来表示:

数组类型:每一维度将使用一个前置的"["字符来描述.如一个定义为"java.lang.Stirng[ ]"类型的二维数组,将被记录为:"[[Ljava/lang/Stirng",一个整型数组"int[]"将被记录为"[I".

用描述符来描述方法: 按照先参数列表,后返回值的顺序来描述,参数列表按照参数的严格顺序放在一组小括号"()"之内。

字段表集合中不会列出从父类或者父接口中继承而来的字段。

二、属性表集合-----静态field字段的初始化

在定义属性字段的过程中,我们有时候会很自然地对 属性字段 直接赋值,如下所示:

public static final int MAX=100;
public  int count=0;  

对于虚拟机而言,上述的两个属性字段赋值的时机是不同的:

  • 对于非静态(即无static修饰)的属性字段的赋值将会出现在实例构造方法()
  • 对于静态的属性字段,有两个选择:1、在静态构造方法()中进行;2 、使用ConstantValue属性进行赋值。

Sun javac编译器对于 静态属性字段 的初始化赋值策略

1)、如果使用finalstatic同时修饰一个属性字段,并且这个字段是基本类型或者String类型的,那么编译器在编译这个字段的时候,会在对应的field_info结构体中
增加一个ConstantValue类型的结构体,在赋值的时候使用这个ConstantValue进行赋值。

2)、如果该属性字段并没有被final修饰,或者不是基本类型或者String类型,那么将在类构造方法()中赋值。

对于上述的public static final init MAX=100; javac编译器在编译此属性字段构建field_info结构体时,除了访问标志、名称索引、描述符索引外,会增加一个ConstantValue类型的属性表。

三、示例

1)先来个网上的例子,图片解释很好

public class Simple {
    private  transient static final String str ="This is a test";
}  

说明

1、字段计数器中的值为0x0001,表示这个类就定义了一个属性字段

2、 字段的访问标志0x009A,这个字段的标志符有:ACC_TRANSIENT、ACC_FINAL、ACC_STATIC、ACC_PRIVATE;

3、 名称索引中的值为0x0005,指向了常量池中的第5项,为“str”,表明这个属性字段的名称是str

4、描述索引中的值为0x0006,指向了常量池中的第6项,为"Ljava/lang/String;",表明这个field字段的数据类型是java.lang.String类型;

5、属性表计数器中的值为0x0001,表明field_info还有一个属性表;

6、属性表名称索引中的值为0x0007,指向常量池中的第7项,为“ConstantValue”,表明这个属性表的名称是ConstantValue,即属性表的类型是ConstantValue类型的;

7、属性长度中的值为0x0002,因为此属性表是ConstantValue类型,它的值固定为2

8、常量值索引 中的值为0x0008,指向了常量池中的第8项,为CONSTANT_String_info类型的项,表示“This is a test” 的常量。在对此field赋值时,会使用此常量对field赋值。

2)自测

package com.jincou.demo.domain;

public class XiaoXiao {
    public String name = "小小";
    private Integer age = 3;
    public static final String sex = "女";
}

接下来看16进制文件和class反编译文件

//1、这里直接截取到访问标志服后的16进制数据,从|开始代表字段集合相关16进制
                                     00
2100 0600 0700 00|00 0300 0100 0800 0900
0000 0200 0a00 0b00 0000 1900 0c00 0900
0100 0d00 0000 0200 0e00 0100 0100 0f00
1000 0100 1100 0000 3300 0200 0100 0000
132a b700 012a 1202 b500 032a 06b8 0004
b500 05b1 0000 0001 0012 0000 000e 0003
0000 0003 0004 0004 000a 0005 0001 0013
0000 0002 0014 

//2、查看 XiaoXiao.class反编译数据信息
Constant pool:
   #1 = Methodref          #7.#21         // java/lang/Object."<init>":()V
   #2 = String             #22            // 小小
   #3 = Fieldref           #6.#23         // com/jincou/demo/domain/XiaoXiao.name:Ljava/lang/String;
   #4 = Methodref          #24.#25        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #5 = Fieldref           #6.#26         // com/jincou/demo/domain/XiaoXiao.age:Ljava/lang/Integer;
   #6 = Class              #27            // com/jincou/demo/domain/XiaoXiao
   #7 = Class              #28            // java/lang/Object
   #8 = Utf8               name
   #9 = Utf8               Ljava/lang/String;
  #10 = Utf8               age
  #11 = Utf8               Ljava/lang/Integer;
  #12 = Utf8               sex
  #13 = Utf8               ConstantValue
  #14 = String             #29            // 女
  #15 = Utf8               <init>
  #16 = Utf8               ()V
  #17 = Utf8               Code
  #18 = Utf8               LineNumberTable
  #19 = Utf8               SourceFile
  #20 = Utf8               XiaoXiao.java
  #21 = NameAndType        #15:#16        // "<init>":()V
  #22 = Utf8               小小
  #23 = NameAndType        #8:#9          // name:Ljava/lang/String;
  #24 = Class              #30            // java/lang/Integer
  #25 = NameAndType        #31:#32        // valueOf:(I)Ljava/lang/Integer;
  #26 = NameAndType        #10:#11        // age:Ljava/lang/Integer;
  #27 = Utf8               com/jincou/demo/domain/XiaoXiao
  #28 = Utf8               java/lang/Object
  #29 = Utf8               女
  #30 = Utf8               java/lang/Integer
  #31 = Utf8               valueOf
  #32 = Utf8               (I)Ljava/lang/Integer;

接下来我们来分析从00 03开始。

//00 03 代表示成员变量的个数,此处为3个。
1)00 01 结合上表代表第一个变量的修饰符为 public
2)00 08 找常量池第8个 name
3)00 09 找常量池第9个 String
4)00 00 用来描述该变量的属性,因为这个变量没有附加属性,所以attributes_count为0,attribute_info为空。
 //接下来直接分析第三个
1)00 19 结合上表 ACC_PUBLIC+ACC_STATIC+ACC_FINAL 刚好19
2)00 0c 找常量池第12个 sex
3)00 09 找常量池第9个 String
4)00 01 代表这个变量有一个附加属性
5)00 0d 找常量池第13个 ConstantValue
6)00 0000 02 属性长度
7)00 0e 找常量池第14个 女

通过这个例子我们注意到:
1)、name = "小小"中的小小并没有出现,这就是上一个例子所说的,因为它不是静态变量所以不属于类,而是属于对象,所以在创建对象的时候,才会出现。
2)、sex = "女" 中的出现了,因为它是静态属性字段,属于类级别的所以出现。

参考

1、深入了解java虚拟机第2版第六章

2、深入理解JVM-Class文件属性集合

只要自己变优秀了,其他的事情才会跟着好起来(少将5)

原文地址:https://www.cnblogs.com/qdhxhz/p/10693324.html

时间: 2024-10-09 17:44:12

【JVM虚拟机】(7)---深入理解Class中-属性集合的相关文章

【JVM虚拟机】(8)--深入理解Class中--方法、属性表集合

#[JVM虚拟机](8)--深入理解Class中--方法.属性表集合 之前有关class文件已经写了两篇博客: 1.[JVM虚拟机](5)---深入理解JVM-Class中常量池 2.[JVM虚拟机](6)---深入理解Class中访问标志.类索引.父类索引.接口索引 3.[JVM虚拟机](7)---深入理解Class中-属性集合 那么这篇博客主要讲有关 方法表集合 相关的理解和代码示例. 方法表集合: 告知该方法是什么修饰符修饰?是否有方法值?返回类型是什么?方法名称,方法参数,还有就是方法内

【JVM虚拟机】(6)---深入理解Class中访问标志、类索引、父类索引、接口索引

JVM(6)访问标志,类索引 上一篇博客讲[JVM虚拟机](5)---深入理解JVM-Class中常量池 我们知道一个class文件正常可以分为7个部分: 魔数与class文件版本 常量池 访问标志 类索引.父类索引.接口索引 字段表集合 方法表集合 属性表集合 那么这篇博客主要讲有关 访问标志 和 类索引.父类索引.接口索引 相关的理解和代码示例. 先通俗的说下这两个的作用: 访问标志: 告知该类是一个什么类型的类,是普通类?还是接口?还是枚举?或者其它类,是用什么修饰符修饰该类的. 类索引.

对JVM虚拟机中方法区的理解

因为jdk8的jvm已经取消了方法区,所以这边先主要介绍jdk8以下版本中方法区相关内容. 1.虚拟机规范中方法区的概念: 原文链接:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5.4 The method area is analogous to the storage area for compiled code of a conventional language or analogous to

java中JVM虚拟机内存模型详细说明

java中JVM虚拟机内存模型详细说明 2012-12-12 18:36:03|  分类: JAVA |  标签:java  jvm  堆内存  虚拟机  |举报|字号 订阅 JVM的内部结构如下图: 一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性能.与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能提高整个应用程序的性能. 本文将从JVM内存模型.GC工作原理,以及GC的几个关键问题进行探讨,从

深入理解JVM虚拟机3:垃圾回收器详解

JVM GC基本原理与GC算法 微信公众号[Java技术江湖]一位阿里 Java 工程师的技术小站.作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux.网络.多线程,偶尔讲点Docker.ELK,同时也分享技术干货和学习经验,致力于Java全栈开发!(关注公众号后回复”Java“即可领取 Java基础.进阶.项目和架构师等免费学习资料,更有数据库.分布式.微服务等热门技术学习视频,内容丰富,兼顾原理和实践,另外也将赠送作者原创的Jav

深入理解JVM虚拟机7:JNDI,OSGI,Tomcat类加载器实现

打破双亲委派模型 JNDI JNDI 的理解 JNDI是 Java 命名与文件夹接口(Java Naming and Directory Interface),在J2EE规范中是重要的规范之中的一个,不少专家觉得,没有透彻理解JNDI的意义和作用,就没有真正掌握J2EE特别是EJB的知识. 那么,JNDI究竟起什么作用?//带着问题看文章是最有效的 要了解JNDI的作用,我们能够从“假设不用JNDI我们如何做?用了JNDI后我们又将如何做?”这个问题来探讨. 没有JNDI的做法: 程序猿开发时,

读深入理解Java中的String(包括JVM)一文总结和提升

读深入理解Java中的String(包括JVM)一文总结和提升 摘要:String作为Java语言中的字符串模拟类,无论是实际的编程工作还是笔试面试过程,都需要我们都String类非常熟悉,对于String类的大部分字符串操作方法,都必须达到熟练运用的程度才行.但是,笔试和面试过程中,面试官往往喜欢问一些String特性相关的题目,来考察面试者对于String基础知识的掌握是否牢固.(本人尚未研读深入理解JVM这本书,分析JVM都是查看网上资料来分析的,若在接下来的内容有分析不到位的地方请见谅和

深入理解JVM虚拟机12:JVM性能管理神器VisualVM介绍与实战

微信公众号[Java技术江湖]一位阿里 Java 工程师的技术小站.作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux.网络.多线程,偶尔讲点Docker.ELK,同时也分享技术干货和学习经验,致力于Java全栈开发!(关注公众号后回复”Java“即可领取 Java基础.进阶.项目和架构师等免费学习资料,更有数据库.分布式.微服务等热门技术学习视频,内容丰富,兼顾原理和实践,另外也将赠送作者原创的Java学习指南.Java程序员面试指

深入理解JavaScript中的属性和特性

深入理解JavaScript中的属性和特性? JavaScript中属性和特性是完全不同的两个概念,这里我将根据自己所学,来深入理解JavaScript中的属性和特性. 主要内容如下: 理解JavaScript中理解对象的本质.理解对象与类的关系.对象与引用类型的关系 对象属性如何进行分类 属性中特性的理解 第一部分:理解JavaScript中理解对象的本质.理解对象与类的关系.对象与引用类型的关系 对象的本质:ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值.对象或者函数.即