《Java虚拟机原理图解》 1.1、class文件基本组织结构

关于变量的几个叫法:

局部变量/全局变量:很好区分根据所在位置。
类变量:静态的全局变量。
类常量:全局的final修饰的变量
静态常量:static final 的字段
常量:这个有几种说法:
,final 修饰的变量
,基本类型和字面值(比如变量,方法,类的名字)也被称为常量(一般在字节码)

简单来说:class文件结构是魔数、副版本号、主版本之后,常量池等:

magic:魔数,文件类型是字节码的一个数字标志,以便jvm识别。
minor_version:次版本号
major_version:主版本号(每个大的版本之间,jdk和jvm可能是不兼容的,以便jvm提前发现)
constant_pool_count:常量计数器,常量的个数
constant_pool[constant_pool_count-]:常量,该字节码中字面量和引用类型:基本类型和字符串的值;类,变量,方法,接口,属性的名字和类型
access_flags:表示类和接口访问权限和属性:比如public,final,super,enum,annotation,abstract
this_class:标识当前字节码是哪个类,对应常量池的一个索引(指向具体的类名称和类型)
super_class:是否有父类,用索引对应常量池中记录的类
interfaces_count:当前类有多少个接口
interfaces[interfaces_count-]:继承了那些接口
fields_count:有多少个字段
fields[fields_count]:具体的字段
methods_count:有多少方法
methods[methods_count]:具体哪些方法
attrributes_count:有多少个属性(属性不是字段)
attributes[attributes_count]:具体属性,(只认识有个内部类的属性,别的都没见过)

具体说下字节码常量池:

《Java虚拟机原理图解》 1.2.2、Class文件中的常量池详解(上)

《Java虚拟机原理图解》 1.2.3、Class文件中的常量池详解(下)

字面量:就是8种基本类型和字符串的值

符号引用:类名的全称也就包括类的包名,字段,方法的名字和类型的名字

注意,以上理解的片面的!不正确的。

字面量:存放的是确切内容的数据,包括了:基本类型(类型和值)和字符串的值,还包括了:类,方法,字段的名字和他们的描述符(类型)的文本表示。
符号引用:存放的是指向具体内容的索引和索引的索引,
包括了:指向字符串值,类名,方法名and类型,字段名and类型,的索引,还包括了指向这些索引的索引项。比如:字段的引用项,方法的引用项。

常量池区域的数据结构:计数器和常量项

常量池计数器(constant_pool_count),它记录着常量池的组成元素常量池项(cp_info)的个数。

常量项的结构:一个类型标志和具体内容

类型标志表:

常量项可以划分的种类:

具体怎么存储:

1,比如常量(常量是带有final的变量):

package com.louis.jvm;
public class IntAndFloatTest {
private final int a = ;
private final int b = ;
private float c = 11f;
private float d = 11f;
private float e = 11f;
}

对应的字节码:可以直接看字节码,也可以通过javap -v IntAndFloatTest 指令

我们发现,对于数值即使定义了多个,常量池也只会存在一个。

特别注意的是:

int类型:
有final标识才会把放到常量池中。并且还会当成字段处理。
有static final 标识只会把值放到常量池中,不会当作字段处理
没有final修饰,只会当作字段处理。(即使字段赋值了,值也是不会放到常量池) float类型:
却不需要final标识值也会放到常量池中。并且当作字段处理。

字段(字段的处理后面有具体介绍)和常量的区别:

字段:
只要没有 static和final同时修饰的变量都当字段处理。
常量:
被final修饰的变量。如果只是final修饰,那么还会当作字段处理。
被final和static同时修饰的变量才会只当作常量处理。 什么是字段处理和常量处理?
常量处理就是:变量和变量值,分别作为常量项存放。
字段处理就是:不管有没有值,都是不存放在常量池中。一个字段包括了多个常量项:名字项,类型项,名字和类型的索引项,字段引用项(索引的索引项)

例子:

public class TestClass{
int a=11;
int aa=11;
final int b=22;
static final int c=33;
float f=44f;
String e="字符串变量";
String ee="字符串变量";
final String eee="常量字符串变量";
public static void main(String[] arg){

字节码如下:

Constant pool:
#1 = Methodref #13.#40 // java/lang/Object."<init>":()V
#2 = Fieldref #12.#41 // TestClass.a:I
#3 = Fieldref #12.#42 // TestClass.aa:I
#4 = Fieldref #12.#43 // TestClass.b:I
#5 = Float 44.0f
#6 = Fieldref #12.#44 // TestClass.f:F
#7 = String #45 // 字符串变量
#8 = Fieldref #12.#46 // TestClass.e:Ljava/lang/String;
#9 = Fieldref #12.#47 // TestClass.ee:Ljava/lang/String;
#10 = String #48 // 常量字符串变量
#11 = Fieldref #12.#49 // TestClass.eee:Ljava/lang/String;
#12 = Class #50 // TestClass
#13 = Class #51 // java/lang/Object
#14 = Utf8 a
#15 = Utf8 I
#16 = Utf8 aa
#17 = Utf8 b
#18 = Utf8 ConstantValue
#19 = Integer 22
#20 = Utf8 c
#21 = Integer 33
#22 = Utf8 f
#23 = Utf8 F
#24 = Utf8 e
#25 = Utf8 Ljava/lang/String;
#26 = Utf8 ee
#27 = Utf8 eee
#28 = Utf8 eeee
#29 = String #52 // 静态常量字符串变量
#30 = Utf8 <init>
#31 = Utf8 ()V
#32 = Utf8 Code
#33 = Utf8 LineNumberTable
#34 = Utf8 main
#35 = Utf8 ([Ljava/lang/String;)V
#36 = Utf8 getA
#37 = Utf8 ()I
#38 = Utf8 SourceFile
#39 = Utf8 TestClass.java
#40 = NameAndType #30:#31 // "<init>":()V
#41 = NameAndType #14:#15 // a:I
#42 = NameAndType #16:#15 // aa:I
#43 = NameAndType #17:#15 // b:I
#44 = NameAndType #22:#23 // f:F
#45 = Utf8 字符串变量
#46 = NameAndType #24:#25 // e:Ljava/lang/String;
#47 = NameAndType #26:#25 // ee:Ljava/lang/String;
#48 = Utf8 常量字符串变量
#49 = NameAndType #27:#25 // eee:Ljava/lang/String;
#50 = Utf8 TestClass
#51 = Utf8 java/lang/Object
#52 = Utf8 静态常量字符串变量
{

2,字符串类型:

虽然多个字符串也只会存储一份,但是存储结构不同,会分成2个常量项来存:1,字符串类型标志和内容的索引;2,文本类型标志和文本内容。

字符也和常量一样分为3种情况(见上面字节码效果):没有final,有final,和final和static

package com.louis.jvm;
public class StringTest {
private String s1 = "JVM原理";
private String s2 = "JVM原理";
private String s3 = "JVM原理";
private String s4 = "JVM原理";
}

字节码的表示:

3,本类和使用到的类型是如何存储:和字符串类似,也许需要两个常量项,只是类型标志不同。

package com.jvm;
import java.util.Date;
public class ClassTest {
private Date date =new Date();
}

字节码的表现形式:

补充一点就是:Object类型会被自动添加,因为所有的类是其子类。

3.1注意:类型只是被声明不会记录到常量池

public  class Other{
private Date date;
public Other()
{
Date da; }

Date类型是不会被记录的,需要改成这样才会:

public  class Other{
public Other()
{
new Date();
}

字节码表现:

特别补充一点:对于文本内容的字符编码是可以设置(之前几个是ask码这个utf8)

4,对字段的存储:需要至少4个常量项(因为有对字段所在的类的指向,所在类的存储需要2个常量项)

CONSTANT_UTF8_info:字段的名字常量项;

CONSTANT_UTF8_info:字段的类型常量项(术语,不叫类型叫字段描述符!!!),

CONSTANT_Name_Type_info(名字和类型的索引):指向名字和类型的索引的常量项;

CONSTANT_Fieldref_info(字段的引用也是索引):指向所在类和【名字和类的索引常量项】的索引的常量项

例子:

package com.louis.jvm;
public class Person {
private String name;
private int age; public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
....

整个结构:

字节码的结构表示:

4.1字段还有一个特别之处是,字段的类型(也就是字段描述符)的表示形式有自己的规则:

比如:

基本类型是首字母大写除了long和boolean.
long是:J;boolean是:Z
引用类型要加"L"(字符串类型是:Ljava/lang/String);
数组类型要加“["(字符串数组是:[Ljava/lang/String);

4.2类中定义了field 字段,在类中的其他地方没用到这些字段,它是不会被编译器放到常量池中的。

比如:私有并且没有方法使用的情况

个人理解常量池对常量和字段的划分是:

字段是没有final修饰的。
常量是有final修饰的,

补充:少了字段的权限(权限不在常量池中)和字段的值(字段值也是不在常量池中)

5,方法的存储:和字段类似,并且方法还要被其他方法使用才会加入到常量池,区别是方法的描述符有多个(包括了参数类型和返回类型)

与字段的区别是:

,方法引用的索引代替了字段引用的索引常量项。
,方法描述符,多个是在一起的格式如:(Lxxx/String,Lxxx/String)Lxxx/String

5.1方法描述符的组成(方法的返回和参数类型):

5.2,字节码中的显示效果:

注意:

方法的描述符(类型)和字段的描述是一样的,但是格式有区别:参数在括号中返回类型在括号后
比如,参数是字符串返回类型是字符串:(Ljava/lang/string)Ljava/lang/string
如果没有参数和返回类型(用“v”表示void):()v

6,如何存类中使用到的接口中的方法,和类方法类似,只有一个常量项有区别:

接口方法引用(CONSTANT_InterfaceMethodref_info)替换了方法引用项

package com.louis.jvm;
public interface Worker{
public void work(); }
public class Boss {
public void makeMoney(Worker worker)
{
worker.work();
} }

字节码显示:

7,java7中的常量项:CONSTANT_MethodType_info,CONSTANT_MethodHandle_info,CONSTANT_InvokeDynamic_info 

这三项主要是为了让Java语言支持动态语言特性

探秘Java 7:JVM动态语言支持详解

执行篇:解析JDK 7的动态类型语言支持

总结:常量池的意义就是把那些经常使用到放到常量池。主要就是文本和值还有引用项(对应文本和值的索引)

class字节码结构(一)(字节码结构和字节常量池的结构)的更多相关文章

  1. JAVA字节码文件之常量池

    一.常量池的内容 一个java类中定义的很多信息都是由常量池来维护和描述的,可以将常量池看作是class文件的资源仓库,比如java类中定义的方法与变量信息.常量池中主要存储两类常量:字面量(文本字符 ...

  2. class字节码结构(零:补充:class结构,常量池,字节码指令)

    JVM高级特性与实践(五):实例探究Class类文件 及 常量池 JVM高级特性与实践(六):Class类文件的结构(访问标志,索引.字段表.方法表.属性表集合) JVM高级特性与实践(七):九大类字 ...

  3. [译] 给PHP开发者的PHP源码-第一部分-源码结构

    文章来自:http://www.hoohack.me/2016/02/04/phps-source-code-for-php-developers-ch 原文:http://blog.ircmaxel ...

  4. 【安卓本卓】Android系统源码篇之(一)源码获取、源码目录结构及源码阅读工具简介

    前言        古人常说,“熟读唐诗三百首,不会作诗也会吟”,说明了大量阅读诗歌名篇对学习作诗有非常大的帮助.做开发也一样,Android源码是全世界最优秀的Android工程师编写的代码,也是A ...

  5. java集合树状结构及源码

    java集合树状结构及源码 最近一直想看一下java集合的源码,毕竟平时用的比较多,但总是感觉是跟着习惯new出来一个对象,比如ArrayList,HashMap等等,所以就简单的看了一下,了解了一下 ...

  6. [源码解析] Pytorch 如何实现后向传播 (2)---- 引擎静态结构

    [源码解析] Pytorch 如何实现后向传播 (2)---- 引擎静态结构 目录 [源码解析] Pytorch 如何实现后向传播 (2)---- 引擎静态结构 0x00 摘要 0x01 Engine ...

  7. [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义

    前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine  ,既然是虚拟机, ...

  8. C语言字节对齐问题详解(对齐、字节序、网络序等)

    首先说明一下,本文是转载自: http://www.cnblogs.com/clover-toeic/p/3853132.html 博客园用的少,不知道怎么发布转载文章,只能暂时这样了. 引言 考虑下 ...

  9. JDK8的JVM内存结构,元空间替代永久代成为方法区及常量池的变化

    JVM的知识这里总结的很详细:https://github.com/doocs/jvm/blob/master/README.md,因此在本博客也不会再对其中的东西重复总结了. 现在很多文章关于JVM ...

随机推荐

  1. Jmeter 如何让变量中包含变量

    在运行Jmeter的过程中,有时候,我们可能会引用一个变量,而这个变量又是由另外一个变量组成的: 譬如我在脚本中要引用变量MappingData1,按照正常的情况,直接就是用${MappingData ...

  2. KbmMW 4.5 发布

    We are happy to announce the release of kbmMW v. 4.50.00 Professional, Enterprise and CodeGear Editi ...

  3. 2018.09.13 poj2728Desert King(最优比率生成树)

    传送门 01分数规划经典题. 不过用krsukal会T掉. 这题用prim反而更快(毕竟是完全图) 因此直接二分+最小生成树搞定. 代码: #include<iostream> #incl ...

  4. 2018.09.05 bzoj1010: [HNOI2008]玩具装箱toy(斜率优化dp)

    传送门 一道经典的斜率优化dp. 推式子ing... 令f[i]表示装前i个玩具的最优代价. 然后用老套路. 我们只考虑把第j+1" role="presentation" ...

  5. json&pickle

    用于序列化的两个模块 json,用于字符串 和 python数据类型间进行转换pickle,用于python特有的类型 和 python的数据类型间进行转换Json模块提供了四个功能:dumps.du ...

  6. Linux服务器部署系列之一—Apache篇(上)

    Linux系统的应用越来越广泛了,学习linux系统的网管兄弟也有增加的趋势.很久以前就有些想法,要将自己学的linux知识整理一下.最近,终于下定决心,挤出时间开始动手写些东西了.虽然不一定好,不过 ...

  7. Tcl写法

    #=============================================================== #Analysi&Synthesis execute_modu ...

  8. Get同步请求

    //同步get请求 //    NSURL: iOS 中的URL存储类,可存储网址或者文件路径         NSString *urlString = @"http://api.map. ...

  9. (并查集)Connections in Galaxy War -- zoj --3261 还没写

    链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261 http://acm.hust.edu.cn/vjudge/ ...

  10. Gridview的RowDataBound事件可以做很多事情

    protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)        {            //如果是绑 ...