`

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  
妙语连珠,喜欢~!

相关推荐

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

    运行时常量池则是在虚拟机运行时载入各个class文件的常量池内容。字符串常量池在JDK8之前位于永久代,但在变化后,它被移出永久代,仍然保留在堆内存中,可能是为了更方便地进行垃圾回收。与此相似,整型常量池也...

    class常量池类型分类.pdf

    ### Java Class 文件中的常量池类型分类 在Java中,每个`.class`文件都包含一个常量池(Constant Pool),它是一个特殊的数据结构,用于存储类或接口的编译期常量,包括直接引用到其他类、字段和方法的信息。常量池...

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

    Java class文件格式之常量池 Java class文件格式之常量池是Java虚拟机(JVM)加载和执行Java类文件的核心组件之一。常量池是class文件的一部分,存储着Java类文件中的各种常量信息,如字符串常量、类名、方法名、...

    java中常量以及常量池

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

    class文件结构浅析

    3. **常量池**:常量池是Class文件中一个非常重要的部分,用于存放各种字面量和符号引用,如类和接口的全限定名、字段的名称和描述符、方法的名称和描述符等。常量池采用数组形式存储,并且每个元素的类型是通过首...

    Java堆,栈和常量池详解

    - 类加载过程中,会把.class文件中的常量池内容复制到方法区的常量池中。 - 方法区的内存回收主要针对常量池。 - **应用场景**: - 字符串字面量的存储。 - 方法、字段的符号引用。 #### 实例解析 下面通过几...

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

    Class文件中的常量池对于理解Java类的结构至关重要,它不仅有助于解释器解析代码,还能帮助开发者调试和理解类的内部结构。 #### 运行时常量池 运行时常量池是在类被加载到JVM中时创建的。当类被加载时,其对应的`...

    jclasslib修改class文件内容

    《使用jclasslib修改Java Class文件内容》 在Java编程世界中,编译后的类文件(.class)是程序的基础,它们包含了字节码指令,是JVM运行时的直接执行对象。然而,通常情况下,我们并不直接操作这些类文件,而是通过...

    class文件编译器.zip

    另外,`javap`命令可以显示`.class`文件的详细信息,包括公共方法、常量池等。 7. **优化与JIT编译**: JVM的Just-In-Time (JIT) 编译器可以在运行时将经常执行的热点代码编译成本地机器代码,以提高性能。HotSpot...

    class文件结构组成.doc

    #### 二、Class文件主要内容解析 1. **Magic Number (魔数)** - 魔数是Class文件的前四个字节,值为`0xCAFEBABE`。它的主要功能是标识该文件为合法的Class文件,便于JVM快速识别和加载。 2. **Version Numbers ...

    java class文件编译

    安装并运行该工具后,可以打开并查看Class文件的详细内容,包括类结构、字节码、常量池等。 下载说明.txt可能包含了获取和安装jclasslib的详细步骤,而新云软件.url可能是指向该工具下载页面的快捷方式。 总之,...

    java class文件查看工具

    Java Class文件遵循特定的文件格式,这个格式由一系列的8位字节构成,包括魔数(Magic Number)、版本信息、常量池、访问标志、类和父类索引、接口索引集合、字段表集合、方法表集合、属性表集合等。这些结构共同...

    java修改class文件工具jbe

    它可以显示类的结构,包括常量池、字段、方法、指令等,并允许用户添加、删除或修改这些元素。 3. **字节码编辑**:通过 JBE,开发者可以直接编辑字节码指令,这在处理性能优化、加密、混淆或调试时特别有用。它也...

    探究Java常量本质及三种常量池(小结)

    运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量...

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

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

    java解析class文件

    Class文件是Java编译器将源代码编译后的结果,包含了类的结构信息、方法定义、常量池等关键数据。理解并能解析Class文件,对于进行JVM优化、字节码分析、动态代理、插桩等高级技术至关重要。 首先,Class文件是以二...

    class文件解析

    1. 常量池:常量池是Class文件中占用空间最大的部分,包含各种字面量(如字符串、整型常量)和符号引用(如类名、字段名、方法名)。常量池的每一个条目都有特定的类型,如CONSTANT_Utf8_info表示字符串,CONSTANT_...

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

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

Global site tag (gtag.js) - Google Analytics