`

Class文件内容及常量池

阅读更多

 

 

当JVM运行Java程序的时候,它会加载对应的class文件,并提取class文件中的信息存放在JVM开辟出来的方法区 内存中。那么这个class文件里面到底有些什么内容呢?

 

一、class文件内容概述

 

class文件是由8bits的字节流组成,全部字节构成了15个有意义的项目。这些项目之间没有任何无意义的字节,因此class文件非常紧凑。占据多字节空间的项目按照高位在前的顺序存放。下面我们详细讨论这些项目:

 

★ magic(魔数)    每个class文件的前4个字节称为魔数,值为0xCAFEBABE。作用在于轻松的辨别class文件与非class文件。

 

★ minor_version、major_version(次、主版本号)   各占2个字节。随着Java技术的发展,class文件的格式会发生变化。版本号的作用在于使得虚拟机能够认识当前加载class的文件格式。从而准确的提取class文件信息。

 

★ constant_pool_count 、constance_pool(常量池)  从这里开始的字节组成了常量池 存储了诸如符号常量、final常量值、基本数据类型的字面值等内容。JVM会将每一个常量构成一个常量表,每个常量表都有自己的入口地址。而实际上在JVM会将这些常量表存储在方法区中一块连续的内存空间中,因此class文件会根据常量表在常量池中的位置对其进行索引。比如常量池中的第一个常量表的索引值就是1,第二个就是2。有的时候常量表A需要常量表B的内容,则在常量表A中会存储常量表B的索引值x。而constant_pool_count就记录了有多少个常量表,或则所有多少个索引值。实际上,常量池中没有索引值为0的常量表,但这缺失的索引值也被记录在 constant_pool_count中,因此 constant_pool_count等于常量表的数量加1。关于常量池的具体内容,我们会在下面详细讲述,并用一个例子来显示整个class文件的内容。

 

★ access_flags(访问标志)   占用2个字节。用来表明该class文件中定义的是类还是接口,访问修饰符是public还是缺省。类或接口是否是抽象的。类是否是final的。

 

★ this_class     占用2个字节。  它是一个对常量池的索引。指向的是常量池中存储类名符号引用的CONSTANT_Class_info常量表(见下面常量池具体结构)。比如this_class=0x0001。则表示指向常量池中的第一个常量表。通常这个表是指向当前class文件所定义的类名。

 

★ super_class  占用2个字节  与this_class类似,指向存放当前class文件所定义类的超类名字的索引的 CONSTANT_Class_info常量表。

 

★ inteface_count、interfaces  interface_count是class文件所定义的类直接实现的接口或父类实现的接口的数量。占2个字节。intefaces包含了对每个接口的 CONSTANT_Class_info常量表的索引。

 

★fields_count、fields   fields_count表明了类中字段的数量 。fields是不同长度的field_info表的序列。这些field_info表中并不包含超类或父接口继承而来的字段。field_info表展示了一个字段的信息,包括字段的名字,描述符和修饰符。如果该字段是final的,那么还会展示其常量值。注意,这些信息有些存放在field_info里面,有些则存放在field_info所指向的常量池中。下面我们阐述一下这个field_info表的格式:

            access_flags(2byte 访问修饰符)  

            name_index(2byte 存储字段名的常量表在常量池中的索引)

            description_index(2byte 存储字段的所属类型的常量表在常量池中的索引)

            attribute_count(2byte 属性表的数量)

            attribute (属性)

其中attribute是由多个attribute_info组成。而JVM规范定义了字段的三种属性:ConstanceValue、Deprecated和Synthetic。

 

★method_count、methods 与字段类似,method_count表明类中方法的数量和每个方法的常量表的索引。methods表明了不同长度的method_info表的序列。该表格式如下:

            access_flags(2byte 访问修饰符)  

            name_index(2byte 存储方法名的常量表在常量池中的索引)

            description_index(2byte 存储方法的返回类型和参数类型的常量表在常量池中的索引)

            attribute_count(2byte 属性表的数量)

            attribute (属性)

其中方法的属性JVM规定了四种:Code,Deprecated,Exceptions,Synthetic。

 

 

二、常量池的具体结构

在Java程序中,有很多的东西是永恒的,不会在运行过程中变化。比如一个类的名字,一个类字段的名字/所属类型,一个类方法的名字/返回类型/参数名与所属类型,一个常量,还有在程序中出现的大量的字面值。比如下面小段源码红色显示的东西。

public class ClassTest {

        private String itemS ="我们 ";

        private final int itemI =100 ;

        public void setItemS (String para ){...}

}

而这些在JVM解释执行程序的时候是非常重要的。那么编译器将源程序编译成class文件后,会用一部分字节分类存储这些永恒不变的红色东西。而这些字节我们就成为常量池。事实上,只有JVM加载class后,在方法区中为它们开辟了空间才更像一个“池”。

 

正如上面所示,一个程序中有很多永恒的红色东西。每一个都是常量池中的一个常量表(常量项)。而这些常量表之间又有不同,class文件共有11种常量表,如下所示:

常量表类型 标志值(占1 byte) 描述
CONSTANT_Utf8 1 UTF-8编码的Unicode字符串
CONSTANT_Integer 3 int类型的字面值
CONSTANT_Float 4 float类型的字面值
CONSTANT_Long 5 long类型的字面值
CONSTANT_Double 6 double类型的字面值
CONSTANT_Class 7 对一个类或接口的符号引用
CONSTANT_String 8 String类型字面值的引用
CONSTANT_Fieldref 9 对一个字段的符号引用
CONSTANT_Methodref 10 对一个类中方法的符号引用
CONSTANT_InterfaceMethodref 11 对一个接口中方法的符号引用
CONSTANT_NameAndType 12 对一个字段或方法的部分符号引用

(1) CONSTANT_Utf8   用UTF-8编码方式来表示程序中所有的重要常量字符串。这些字符串包括: ①类或接口的全限定名, ②超类的全限定名,③父接口的全限定名, ④类字段名和所属类型名,⑤类方法名和返回类型名、以及参数名和所属类型名。⑥字符串字面值

      表格式:   tag(标志1:占1byte)       length(字符串所占字节的长度,占2byte)      bytes(字符串字节序列)

 

(2) CONSTANT_Integer、 CONSTANT_Float、 CONSTANT_Long、 CONSTANT_Double  所有基本数据类型的字面值。比如在程序中出现的1用CONSTANT_Integer表示。3.1415926F用 CONSTANT_Float表示。

      表格式:   tag             bytes(基本数据类型所需使用的字节序列)

 

(3) CONSTANT_Class  使用符号引用来表示类或接口。我们知道所有类名都以 CONSTANT_Utf8表的形式存储。但是我们并不知道 CONSTANT_Utf8表中哪些字符串是类名,那些是方法名。因此我们必须用一个指向类名字符串的符号引用常量来表明。

     表格式:   tag    name_index(给出表示类或接口名的CONSTANT_Utf8表的索引)

 

(4) CONSTANT_String  同 CONSTANT_Class,指向包含字符串字面值的 CONSTANT_Utf8表。

    表格式:   tag    string_index(给出表示字符串字面值的CONSTANT_Utf8表的索引)

 

(5) CONSTANT_Fieldref CONSTANT_Methodref、 CONSTANT_InterfaceMethodref     指向包含该字段或方法所属类名的 CONSTANT_Utf8表,以及指向包含该字段或方法的名字和描述符的 CONSTANT_NameAndType

    表格式:   tag   class _index(给出包含所属类名的CONSTANT_Utf8表的索引)  name_and_type_index(包含字段名或方法名以及描述符的 CONSTANT_NameAndType表 的索引)

 

(6) CONSTANT_NameAndType  指向包含字段名或方法名以及描述符的 CONSTANT_Utf8表。

    表格式:   tag    name_index(给出表示字段名或方法名的CONSTANT_Utf8表的索引)  type_index(给出表示描述符的CONSTANT_Utf8表的索引)

 

下面是我将一个源程序编译成class文件后,对文件中的每一个字节的分析,可以更好的理解class文件的内容以及常量池的组成。

 

 

三、TestClass.class 文件实例分析

//源代码
package hr.test;
//ClassTest类
public class ClassTest {
	private int itemI=0;  //itemI类字段
	private static String itemS="我们"; //itemS类字段
	private final float PI=3.1415926F;  //PI类字段
	//构造器方法
	public ClassTest(){
	}
	//getItemI方法
	public int getItemI(){
		return this.itemI;
	}
	//getItemS方法
	public static String getItemS(){
		return itemS;
	}
	//main主方法
	public static void main(String[] args) {
		ClassTest ct=new ClassTest();
	}
}

 

TestClass.class 字节码分析(字节顺序从上到下,从左到右。每个字节用一个0-255的十进制整数表示)

 

     202 254 186 190   -- 魔数                                                                                                 
     0 0     -- 次版本号                                                                                                                                   
     0 50   -- 主版本号                                                                                                               

     0 43   -- 常量池中常量表的数量有42个,下面红色括号中的数据表明该常量表所在常量池中的索引,从索引1开始

(1) 7 0 2  -- 对类ClassTest的符号引用(7为标志  02指向了常量池的索引2的位置)

(2) 1 0 17 104 114 47 116 101 115 116 47 67 108 97 115 115 84 101 115 116  -- 类全限定名hr\test\ClassTest
(3) 7 0 4    -- 对类Object的符号引用

(4) 1 0 16 106 97 118 97 47 108 97 110 103 47 79 98 106 101 99 116   -- 超类全限定名 java/lang/Object   
(5) 1 0 5 105 116 101 109 73    --  第1个类字段名 itemI  
(6) 1 0 1 73    --  I  第1个类字段类型为整型
(7) 1 0 5 105 116 101 109 83    --  第2个类字段名 itemS
(8) 1 0 18 76 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 59    --  第2个类字段类型的全限定名 Ljava/lang/String
(9) 1 0 2 80 73 -- 第3个类字段名PI
(10) 1 0 1 70  -- 第3个类字段类型为float
(11) 1 0 13 67 111 110 115 116 97 110 116 86 97 108 117 101    ---  第3个类字段为常量ConstantValue

(12) 4 64 73 15 218   -- 第3个类字段float字面值,占4bytes(3.1415926)
(13) 1 0 8 60 99 108 105 110 105 116 62    -- <clinit>  初始化方法名
(14) 1 0 3 40 41 86     -- ()V 方法的返回类型为void

(15) 1 0 4 67 111 100 101     -- Code
(16) 8 0 17 -- String字符串字面值(0 17表示索引1 7)
(17) 1 0 6 230 136 145 228 187 172    -- "我们"
(18) 9 0 1 0 19  -- 指向 第2个 字段的引用(0 1指向索引1,0 19指向索引19)
(19) 12 0 7 0 8   --指向 第2个 字段的名字和描述符的索引,
(20) 1 0 15 76 105 110 101 78 117 109 98 101 114 84 97 98 108 101    -- LineNumberTable
(21) 0 18 76 111 99 97 108 86 97 114 105 97 98 108 101 84 97 98 108 101    -- LocalVariableTable
(22) 1 0 6 60 105 110 105 116 62   -- <init>   表示初始化方法名
(23) 10 0 3 0 24 --  指向父类Object的构造器方法,0 3表示父类名常量表的索引,0 24表示存放该方法名称和描述符的引用的常量表的索引
(24) 12 0 22 0 14  --  指向方法名和描述符的常量表的索引。0 22是方法名的常量表索引,0 14是描述符的常量表索引
(25) 9 0 1 0 26    -- 指向第1个字段的引用, 0 1表示字段所属类型的索引,0 26表示字段名和描述符的索引
(26) 12 0 5 0 6    -- 指向第1个字段的名字和描述符的索引
(27) 9 0 1 0 28    -- 指向第3个字段的引用, 0 1表示字段所属类型的索引,0 28表示字段名和描述符的索引
(28) 12 0 9 0 10  -- 指向第3个字段的名字和描述符的索引
(29) 1 0 4 116 104 105 115    --  隐含参数符号this
(30) 1 0 11 76 67 108 97 115 115 84 101 115 116 59    --  LClassTest;
(31) 1 0 8 103 101 116 73 116 101 109 73    - - 方法名 getItemI
(32) 1 0 3 40 41 73    -- ()I  方法描述符:返回类型int
(33) 1 0 8 103 101 116 73 116 101 109 83   --  方法名 getItemS
(34) 1 0 20 40 41 76 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 59     --- 方法描述符()Ljava/lang/String;
(35) 1 0 4 109 97 105 110     --  主方法名main
(36) 1 0 22 40 91 76 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 59 41 86    ---  ()Ljava/lang/String;)V  主方法中的参数的字符串数组类型名
(37) 10 0 1 0 24    指向当前 ClassTest 类的构造器方法,0 1表示存放当前类名的常量表的索引。0 24是存放方法名和描述符的符号引用的常量表索引。  
(38) 1 0 4 97 114 103 115  -- 参数args
(39) 1 0 19 91 76 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 59   -- 字符串数组 [Ljava/lang/String;
(40) 1 0 2 99 116    ---  对象符号ct
(41) 1 0 10 83 111 117 114 99 101 70 105 108 101    -- SourceFile
(42) 1 0 14 67 108 97 115 115 84 101 115 116 46 106 97 118 97    -- ClassTest.java    

 

       0 33 ---- access_flag 访问标志  public
       0 1   ---- this_class  指向当前类的符号引用在常量池中的索引
       0 3  ---- super_class

       0 0 ---- inteface_count接口的数量

       0 3   ---  field_count字段的数量

       // 字段 itemI
       0 2  ---- private 修饰符
       0 5  ---- 字段名在常量池中的索引,字段itemI
       0 6   ---- 字段的描述符(所属类型)在常量池中的索引
       0 0   ---  字段的属性信息表(attribute_info)的数量
      
// 字段 itemS
       0 10   ----  private static 修饰符
       0 7  ---字段名在常量池中的索引,字段itemS
       0 8  ---字段的描述符(所属类型)在常量池中的索引
       0 0  ---  字段的属性信息表(attribute_info)的数量
       
// 字段 PI  
       0 18   -- private final 修饰符
       0 9 ---字段名在常量池中的索引,//字段PI
       0 10 ---字段的描述符(所属类型)在常量池中的索引
       0 1  --- 字段的属性信息表(attribute_info)的数量
       0 11   --- 属性名在常量池中的索引。即ConstantValue
       0 0 0 2 --- 属性所占的字节长度
       0 12   --- 属性值在常量池中的索引。即常量字面值


       0 5  -- Method_count方法的数量
       //类的静态数据初始化方法<clinit>
       0 8 ---- static 修饰符(所有的初始化方法都是static的)
       0 13 --- 在常量池中的索引。初始化方法名<clinit>,该方法直接由JVM在特定的时候调用,并非由字节码生成。
       0 14 --- 在常量池中的索引。返回类型为void。

       0 1 --- 属性数量
       0 15 -- 属性名 在常量池中的索引。即code
       0 0 0 42 ---  属性所占的字节长度2
       0 1 0 0 0 0 0 6 18 16 179 0 18 177 0 0 0 2 0 20 0 0 0 10 0 2 0 0 0 5 0 5 0 2 0 21 0 0 0 2 0 0 ---该方法的字节码指令序列和其他信息
       //类的普通实例数据的初始化方法,针对类构造器生成的<init>方法。
       0 1 --- public 修饰符
       0 22 --- 构初始化方法名<init>
       0 14 --- 构造器的返回类型为void
       0 1  --- 属性数量
       0 15 ---  属性名在常量池中的索引。即Code
       0 0 0 70 -- 属性所占的字节长度70
       0 2 0 1 0 0 0 16 42 183 0 23 42 3 181 0 25 42 18 12 181 0 27 177 0 0 0 2 0 200 0 0 18 0 4 0 0 0 8 0 4 0 4 0 9 0 6 0 15 0 9 0 21 0 0 0 12 0 10 0 0 16 0 29 0 30 0 0 ---该方法的字节码指令序列和其他信息
       //getItemI方法
       0 1 --- public 修饰符
       0 31 ---  在常量池中的索引。方法名getItemI
       0 32 ---  在常量池中的索引。方法返回类型为int
       0 1 -- 属性数量
       0 15  --- 属性名在常量池中的索引。即Code
       0 0 0 47 ---  属性所占的字节长度70
       0 1 0 1 0 0 0 5 42 180 0 25 172 0 0 0 2 0 20 0 0 0 6 0 1 0 0 0 12 0 21 0 0 0 12 0 1 0 0 0 5 0 29 0 30 0 0  --- 该方法的字节码指令序列和其他信息
       //getItemS方法
       0 9 --- public static 修饰符
       0 33 ---  在常量池中的索引。方法名getItemS
       0 34 - -- 在常量池中的索引。方法返回类型为String
       0 1 --- 属性数量
       0 15 -- 属性名在常量池中的索引。即Code
       0 0 0 36 ---  属性所占的字节长度36
       0 1 0 0 0 0 0 4 178 0 18 176 0 0 0 2 0 20 0 0 0 6 0 1 0 0 0 16 0 21 0 0 0 2 0 0 --该方法的字节码指令序列和其他信息
       //main方法
       0 9 --- public static 修饰符
       0 35 ---  在常量池中的索引。主方法名main
       0 36 -- 在常量池中的索引。方法返回类型为String[]
       0 1 ---  属性数量
       0 15  ---  属性名在常量池中的索引。即Code
       0 0 0  65 ---  属性所占的字节长度36
       0 2 0 2 0 0 0 9 187 0 1 89 183 0 37 76 177 0 0 0 2 0 20 0 0 0 10 0 2 0 0 0 20 0 8 0 21 0 21 0 0 0 22 0 2 0 0 0 9 0 38 0 39 0 0 0 8 0 1 0 40 0 30 0 1 0 1 0 41 0 0 0 2 0 42

 

 

我们分析上面的字节码例子,不难看出:

 

蓝色背景的常量池字节码区域:

(1) 所有的字面值都是存放在常量池中的。 特别注意的是“我们”这个字符串常量也是在常量池中的。如果一个程序出现多个“我们”,那么常量池中也只会有一个。另外,也正是因为“我们”存放在常量池中,使得一些字符串的==比较变的需要琢磨了。

(2)ClassTest并没有任何显示的父类。但在常量池中,我们发现有Object的符号常量存在。 这也证实了在Java中,任何类都直接或间接继承了Object的,而Object并不需要在代码中显示继承,JVM会帮我们做到这一点。

(3)常量池中有一个隐含参数this的符号常量。即使程序中不存在this,JVM也会悄悄的设置一个这样的对象。

 

绿色背景的类字段字节码区域:

(1)字段PI是浮点型常量,在编译期的字节码中就已经指定好了PI的字面值存储在常量池中的某个索引内 。这一点也证实了Java中的常量在编译期就已经得到了值,在运行过程中是无法改变的。

 

橙色背景的类方法字节码区域:

(1)主方法main是作为ClassTest的类方法存在的,在字节码中main和其他的类方法并没有什么区别。 实际上,我们也确实可以通过ClassTest.main(..)来调用ClassTest中的main方法。

 

(2)在class文件常量池字节码中有两个比较特别的方法名符号:<clinit>和<init>。其中<clinit>方法是编译器自己生成的,编译器会把类静态变量的直接初始化语句和静态初始化语句块的代码都放到了class文件的<clinit>方法中。而对所有非静态非常量数据域的初始化工作要靠<init>方法来完成。针对每一个类的构造方法,编译器都会产生一个<init>方法。即使是缺省构造器也不例外。

 

分享到:
评论
15 楼 nothing0318 2013-11-07  
博主分析的很好。
另外推荐一款好工具,用来分析class文件的: http://sourceforge.net/projects/classeditor/files/
14 楼 goodscript 2011-12-27  
xm_king 写道
Heart.X.Raid 写道
xiaolu123456 写道
LZ上面的那些TestClass.class 字节码,怎么是这样的啊,如何出来的,请教!


写个java小程序,用IO流把class文件的一个字节一个字节的读出来,然后解析字节的含义

或者用UE

楼主能否把你写的java小程序共享一下。
在你解析class文件的时候。我有一点不明白,如何区分常量池中的项
如果是根据常量表类型标识来区分的话:
魔数:cafebabe
次版本号:0
主版本号:49
常量表长度:43
070002
01001168722f746573742f436c61737354657374
0700
04
0100106a6176612f6c616e672f4f626a656374
0100
056974656d49
0100
0149
0100
056974656d53
0100124c6a6176612f6c616e672f537472696e673b
0100025049
0100
0146
01000d436f6e7374616e7456616c7565
0440490fda
0100
083c636c696e69743e
0100
03282956
0100
04436f6465
080011
0100
06e68891e4bbac
0900
010013
0c00
0700
08
01000f4c696e654e756d6265725461626c65
0100124c6f63616c5661726961626c655461626c65
0100
063c696e69743e
0a00
030018
0c0016000e
0900
01001a
0c00
0500
06
0900
01001c
0c00
0900
0a
0100
0474686973
0100134c68722f746573742f436c617373546573743b
0100
086765744974656d49
0100
03282949
0100
086765744974656d53
01001428294c6a6176612f6c616e672f537472696e673b
0100
046d61696e
010016285b4c6a6176612f6c616e672f537472696e673b2956
0a00
010018
0100
0461726773
0100135b4c6a6176612f6c616e672f537472696e673b
0100026374
0100
0a536f7572636546696c65
01000e436c617373546573742e6a617661002100
0100
03000000
03000200
0500
06000000
0a00
0700
080000001200
0900
0a00
0100
0b0000000200
0c00
0500
08000d000e00
01000f0000002a00
010000000000
061210b30012b1000000020014000000
0a0002000000
0600
0500
04001500000002000000
010016000e00
01000f00000046000200
01000000102ab700172a
03b500192a12
0cb5001bb10000000200140000001200
04000000
0a00
0400
0500
0900
07000f00
0b0015000000
0c00
0100000010001d001e000000
01001f002000
01000f0000002f00
0100
01000000
052ab40019ac000000020014000000
0600
010000000f0015000000
0c00
01000000
05001d001e000000
090021002200
01000f0000002400
010000000000
04b20012b0000000020014000000
0600
0100000014001500000002000000
090023002400
01000f0000004100020002000000
09bb00
0159b700254cb1000000020014000000
0a00020000001900
08001a0015000000160002000000
0900260027000000
0800
010028001e00
0100

13 楼 xm_king 2011-07-16  
Heart.X.Raid 写道
xiaolu123456 写道
LZ上面的那些TestClass.class 字节码,怎么是这样的啊,如何出来的,请教!


写个java小程序,用IO流把class文件的一个字节一个字节的读出来,然后解析字节的含义

或者用UE
12 楼 Rorschach 2010-12-31  
好文~ 只是LZ能不能讲一下class文件里字段与该字段字面值的联系在哪(比如itemS和“我们”)?貌似LZ给出的编译后的代码中二者是没有关系的
11 楼 Heart.X.Raid 2010-11-20  
反编译的只不过用一种程序把Java 字节码翻译成我们人能看的懂的代码,而我读Class文件中的字节只是JVM能够读懂的代码而已。我只是想反映JVM是如何理解Class文件的。
10 楼 xiaolu123456 2010-11-19  
Heart.X.Raid 写道
xiaolu123456 写道
LZ上面的那些TestClass.class 字节码,怎么是这样的啊,如何出来的,请教!


写个java小程序,用IO流把class文件的一个字节一个字节的读出来,然后解析字节的含义

这个跟javap反编译出来的字节码有什么关系,这个比Java反编译后的字节码我觉得更难懂啊,lz能不能就反编译后的字节码详细讲述一下class文件的内容和他们的联系啊!
9 楼 Heart.X.Raid 2010-11-19  
xiaolu123456 写道
LZ上面的那些TestClass.class 字节码,怎么是这样的啊,如何出来的,请教!


写个java小程序,用IO流把class文件的一个字节一个字节的读出来,然后解析字节的含义
8 楼 xiaolu123456 2010-11-18  
LZ上面的那些TestClass.class 字节码,怎么是这样的啊,如何出来的,请教!
7 楼 Heart.X.Raid 2010-09-01  
gstarwd 写道
问个问题 常量池 在运行期  在哪里?工作内存 还是主存?


我5L的解释答非所问,我可能没有理解你的意思。

我认为主存是所有线程可以共享的区域,而工作内存是线程执行指令的地方。那么我觉得常量池应该放在主存中,而每个方法运行时需要的栈帧应该放在工作内存中。
6 楼 laststand 2010-09-01  
gstarwd 写道
问个问题 常量池 在运行期  在哪里?工作内存 还是主存?

你也来这里
5 楼 Heart.X.Raid 2010-08-28  
常量池在运行期在内存中,JVM管理内存会将内存分成方法区,堆,栈,程序计数器等空间。而常量池就位于方法区中
4 楼 gstarwd 2010-08-28  
问个问题 常量池 在运行期  在哪里?工作内存 还是主存?
3 楼 niumd 2010-07-09  
niumd 写道
常量计数constant_pool_count后面的字节应该是:07 00 02,
constant_pool结构类型为cp_info{u1 tag,u1 info},tag=07代表constant_class,info一个字节应该是00,楼主请问为何是02呢,这点不明白;

明白了;呵呵谢谢,写的不错
2 楼 niumd 2010-07-09  
常量计数constant_pool_count后面的字节应该是:07 00 02,
constant_pool结构类型为cp_info{u1 tag,u1 info},tag=07代表constant_class,info一个字节应该是00,楼主请问为何是02呢,这点不明白;
1 楼 2001430 2010-06-19  
妙语连珠,喜欢~!

相关推荐

    JVM常量池教程吐血整理干货.md

    Class文件常量池主要存放两大常量:字面量和符号引用。 字面量: 字面量分为文本字符串(如: "abc",1等)和用final修饰的成员变量(实例变量和静态变量) 符号引用: 符号引用包括三种:类的全限定名,方法名和描述符,...

    java中常量以及常量池

    1、举例说明 变量 常量 字面...  静态常量池:*.class文件中的常量池,class文件中的常量池不仅仅包含字符串,数值字面量,还包含类、方法的信息,占用class文件绝大部分空间。  运行时常量池:是jvm虚拟机在完成类装

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

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

    RodJohn#jvm#内存区域_运行时常量池1

    常量池静态常量池即*.class文件中的常量池,用于存放字面量和符号引用运行时常量池是jvm运行期间,存储常量的数据结构运行时常量池概念运行时常量池(Runti

    Java常量池解析与字符串intern简介

    在Java应用程序运行时,Java虚拟机会保存一份内部的运行时常量池,它区别于class文件的常量池,是class文件常量池映射到虚拟机中的数据结构。 关于class文件常量池的部分可以参考之前的博文实例探索Class文件。  1...

    Java常量池理解与总结

     在Class文件结构中,头的4个字节用于存储魔数Magic Number,用于确定一个文件是否能被JVM接受,再接着4个字节用于存储版本号,前2个字节存储次版本号,后2个存储主版本号,再接着是用于存放常量的常量池,由于...

    [学习笔记]jdk1.7_class文件结构分析

    jdk1.7_class文件结构分析,常量池分析;jdk1.7_class文件结构分析,常量池分析;

    Class文件结构

    主要内容包含Class文件的组成要素,魔数,版本号,常量池等内容

    jclasslib 工具修改.class文件,同时需要jad.exe做辅助

    打开之后找到 要修改提示信息 的class文件 这里找到的是GenEntity 找到对应需要修改的代码所在的方法名 我这里包含提示信息的这段代码在方法 getAllDataBase() 如下图: 2.用jd-gui或者winrar把GenEntity.class 解压...

    JVM执行子系统-JVM进阶

    常量池中常量的数量是不固定的,所以在常量池的入口需要放置一项 u2 类型的数据,代 表常量池容量计数值(constant_pool_count)。与 Java 中语言习惯不一样的是,这个容 量计数是从 1 而不是 0 开始的 常量池中主要...

    JVM虚拟机从入门到实战视频教程.zip

    目录网盘文件永久链接 001-JVM课程导读 002-第一章-JVM课程简介 003-虚拟机概念 004-JVM的定义 005-JVM规范 006-JVM产品 ...025-【分析】常量池总数 026-【分析】class文件中的常量 027..............

    Ming:Class文件解析器

    现在基本可以完整的展示整个class文件的信息0.1.2进一步优化输出的信息,现在可以在打印信息的时候直接显示出常量池索引所指向的常量0.1.3现在可以打印出方法的操作码0.1.4修复部分bug0.1.5现在可以正常打印出属性,...

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

    特殊字符串出现在class文件中的常量池中,本着循序渐进和减少跨度的原则, 首先把class文件中的特殊字符串做一个详细的介绍, 然后再回过头来继续讲解常量池,对java class 文件格式相关知识感兴趣的的朋友一起学习...

    自己动手写Java虚拟机 张秀宏 著

    高清非扫描版 带目录 SBN:978-7-111-53413-6 目录 前言 第1章 命令行工具 1.1 准备工作 1.1.1 安装JDK 1.1.2 安装Go 1.1.3 创建目录结构 ...3.3 解析常量池 3.3.1 ConstantPool结构体 3.3.2 ConstantInfo接口

    Core_Java虚拟机规范中文版

    Java虚拟机 内存管理 优化 Class文件 常量池

    Java思维导图

    Java代码在进行Javac编译的时候,并不像C和C++那样有“连接”这一步骤,而是在虚拟机加载Class文件的时候...当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中。

    Java7虚拟机规范(高清带目录)

    《Java虚拟机规范(Java SE 7版)》是Java领域最重要和最...第4章深入分析了用来表示编译后的类和接口的class文件格式,主要包括ClassFile结构、描述符与签名、常量池、字段、方法、属性、代码约束与class文件校验等。

    JVM性能优化相关问题-面试-进阶

    Java 类加载需要经历一下 7 个过程: ...主次版本号是否在当前虚拟机范围内,常量池中的常量是否 有不被支持的类型. • 元数据验证:对字节码描述的信息进行语义分析,如这个类是 否有父类,是否集成了不被继承的类等。

    JCLASSLIB

    可以更改CLASS文件的函数,常量池,循环语句 使用时需配置 环境变量 架构核心包

    java虚拟机规范 jdk8.

     深入分析用来表示编译后的类和接口的class文件格式,主要包括ClassFile文件结构、描述符、常量池、字段、方法、属性、格式检查、代码约束与class文件校验等。  定义Java虚拟机启动以及类和接口的加载、链接和初始...

Global site tag (gtag.js) - Google Analytics