【JVM虚拟机】(7)---深入理解Class中-属性集合
深入理解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_index和descriptor_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)、如果使用final和static同时修饰一个属性字段,并且这个字段是基本类型或者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版第六章
只要自己变优秀了,其他的事情才会跟着好起来(少将5)
【JVM虚拟机】(7)---深入理解Class中-属性集合的更多相关文章
- 万字长文深入理解java中的集合-附PDF下载
目录 1. 前言 2. List 2.1 fail-safe fail-fast知多少 2.1.1 Fail-fast Iterator 2.1.2 Fail-fast 的原理 2.1.3 Fail- ...
- 彻底理解Oracle中的集合操作与复合查询
--Oracle中的复合查询 复合查询:包含集合运算(操作)的查询 常见的集合操作有: union: 两个查询的并集(无重复行.按第一个查询的第一列升序排序) union all:两个查询的并集(有重 ...
- 【JVM虚拟机】(8)--深入理解Class中--方法、属性表集合
#[JVM虚拟机](8)--深入理解Class中--方法.属性表集合 之前有关class文件已经写了两篇博客: 1.[JVM虚拟机](5)---深入理解JVM-Class中常量池 2.[JVM虚拟机] ...
- JVM虚拟机知识问答总结(简单复习,快速回忆!)
写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...
- 【JVM虚拟机】(6)---深入理解Class中访问标志、类索引、父类索引、接口索引
JVM(6)访问标志,类索引 上一篇博客讲[JVM虚拟机](5)---深入理解JVM-Class中常量池 我们知道一个class文件正常可以分为7个部分: 魔数与class文件版本 常量池 访问标志 ...
- 【JVM虚拟机】(5)---深入理解JVM-Class中常量池
深入理解Class---常量池 一.概念 1.jvm生命周期 启动:当启动一个java程序时,一个jvm实例就诞生了,任何一个拥有main方法的class都可以作为jvm实例运行的起点. 运行:mai ...
- 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)
欢迎一起学习 <提升能力,涨薪可待篇> <面试知识,工作可待篇 > <实战演练,拒绝996篇 > 欢迎关注我博客 也欢迎关注公 众 号[Ccww笔记],原创技术文章 ...
- 对JVM虚拟机中方法区的理解
因为jdk8的jvm已经取消了方法区,所以这边先主要介绍jdk8以下版本中方法区相关内容. 1.虚拟机规范中方法区的概念: 原文链接:http://docs.oracle.com/javase/spe ...
- 深入理解JVM虚拟机7:JNDI,OSGI,Tomcat类加载器实现
打破双亲委派模型 JNDI JNDI 的理解 JNDI是 Java 命名与文件夹接口(Java Naming and Directory Interface),在J2EE规范中是重要的规范之中的一 ...
随机推荐
- Ocelot中文文档-负载均衡
Ocelot能通过可用的下游服务对每个ReRoute进行负载平衡. 这意味着您可以扩展您的下游服务,并且Ocelot可以有效地使用它们. 可用的负载均衡器的类型是: LeastConnection - ...
- PHP 中的 __FILE__ 和__DIR__常量
__DIR__ :当前内容写在哪个文件就显示这个文件目录 __FILE__ : 当前内容写在哪个文件就显示这个文件目录+文件名 比如文件 b.php 包含如下内容: <?php $basedir ...
- 异步任务spring @Async注解源码解析
1.引子 开启异步任务使用方法: 1).方法上加@Async注解 2).启动类或者配置类上@EnableAsync 2.源码解析 虽然spring5已经出来了,但是我们还是使用的spring4,本文就 ...
- JavaScript(三、DOM文档对象模型)
一.什么是DOM DOM 是 Document Object Model(文档对象模型)的缩写. DOM 是 W3C(万维网联盟)的标准. DOM 定义了访问 HTML 和 XML 文档的标准: &q ...
- 基于SpringBoot + Mybatis实现SpringMVC Web项目
一.热身 一个现实的场景是:当我们开发一个Web工程时,架构师和开发工程师可能更关心项目技术结构上的设计.而几乎所有结构良好的软件(项目)都使用了分层设计.分层设计是将项目按技术职能分为几个内聚的部分 ...
- Unity文档阅读 第一章 入门
Before you learn about dependency injection and Unity, you need to understand why you should use the ...
- 【手记】解决启动SQL Server Management Studio 17时报Cannot find one of more components...的问题
刚装好SSMS 17.1准备体验,弹出: 一番搜索,普遍办法都是安装VS2015独立shell.删除某个注册表项什么的,没用,首先这个shell我是装了的,然后也没有那个注册表项.我自己尝试过重装sh ...
- RCTF 2018线上赛 writeup
苦逼的RCTF,只进行了两天,刚好第二天是5.20,出去xxx了,没法打比赛,难受.比赛结束了,还不准继续提交flag进行正确校验了,更难受. 下面是本次ctf解题思路流程 后面我解出的题会陆续更新上 ...
- 运维监控利器Nagios之:nagios配置详解
http://ixdba.blog.51cto.com/2895551/752870 一.nagios配置过程详解 1.nagios默认配置文件介绍 nagios安装完毕后,默认的配置文件在/usr ...
- Doctype作用?标准模式与兼容模式各有什么区别?
Doctype作用?标准模式与兼容模式各有什么区别? DOCTYPE是document type(文档类型)的简写,用来告诉浏览器的解析器使用哪种HTML或XHTML规范解析页面.DOCTYPE不存在 ...