- 浏览: 899506 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
小宇宙_WZY:
膜拜一下大神,解决了我一个大问题,非常感谢 orz
【解惑】深入jar包:从jar包中读取资源文件 -
JKL852qaz:
感谢,遇到相同的问题!
【解惑】深入jar包:从jar包中读取资源文件 -
lgh1992314:
为什么java中调用final方法是用invokevirtua ...
【解惑】Java动态绑定机制的内幕 -
鲁曼1991:
说的都有道理,protected只能被同一级包的类所调用
【解惑】真正理解了protected的作用范围 -
鲁曼1991:
...
【总结】String in Java
当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>方法。即使是缺省构造器也不例外。
评论
另外推荐一款好工具,用来分析class文件的: http://sourceforge.net/projects/classeditor/files/
写个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
写个java小程序,用IO流把class文件的一个字节一个字节的读出来,然后解析字节的含义
或者用UE
写个java小程序,用IO流把class文件的一个字节一个字节的读出来,然后解析字节的含义
这个跟javap反编译出来的字节码有什么关系,这个比Java反编译后的字节码我觉得更难懂啊,lz能不能就反编译后的字节码详细讲述一下class文件的内容和他们的联系啊!
写个java小程序,用IO流把class文件的一个字节一个字节的读出来,然后解析字节的含义
我5L的解释答非所问,我可能没有理解你的意思。
我认为主存是所有线程可以共享的区域,而工作内存是线程执行指令的地方。那么我觉得常量池应该放在主存中,而每个方法运行时需要的栈帧应该放在工作内存中。
你也来这里
constant_pool结构类型为cp_info{u1 tag,u1 info},tag=07代表constant_class,info一个字节应该是00,楼主请问为何是02呢,这点不明白;
明白了;呵呵谢谢,写的不错
constant_pool结构类型为cp_info{u1 tag,u1 info},tag=07代表constant_class,info一个字节应该是00,楼主请问为何是02呢,这点不明白;
发表评论
-
Java内存泄露问题
2010-08-29 08:49 5942内存泄露 ... -
JVM加载class文件的原理
2010-08-26 11:30 39031当Java编译器编译好.class文件之后,我们需要 ... -
JVM垃圾回收机制总结(8) :反思和参考资料
2010-08-26 11:25 4033垃圾回收的悖论 ... -
JVM垃圾回收机制总结(7) :调优方法
2010-08-26 11:23 4441JVM调优工具 Jconsole,j ... -
JVM垃圾回收机制总结(6) :透视Java的GC特性
2010-08-26 11:21 5375全文转载: http://topic.csdn.net/u/2 ... -
JVM垃圾回收机制总结(5) :JDK垃圾收集器的配置命令
2010-08-24 15:48 6087全文转载:http://pengjiaheng.iteye.c ... -
JVM垃圾回收机制总结(4) :新一代的垃圾回收算法
2010-08-23 16:02 3782全文转载: http://pengji ... -
JVM垃圾回收机制总结(3) :按代垃圾收集器
2010-08-23 15:42 5008全文转载:http://pengjiaheng.iteye.c ... -
JVM垃圾回收机制总结(2) :基本算法概述
2010-08-23 13:47 52501、引用计数收集器 (Reference Countin ... -
JVM垃圾回收机制总结(1) :一些概念
2010-08-23 09:30 4383全文转载:http://pengjia ... -
Java的垃圾回收机制
2010-06-24 16:16 105全文转载: http://topic ... -
Java 虚拟机体系结构
2010-05-26 20:43 24411众所周知,Java源代码被 ... -
J2SE 四大技术体系
2010-05-10 17:12 4641讲到Java,很容易就想到程序设计语言。实际上,Java技术包 ...
相关推荐
运行时常量池则是在虚拟机运行时载入各个class文件的常量池内容。字符串常量池在JDK8之前位于永久代,但在变化后,它被移出永久代,仍然保留在堆内存中,可能是为了更方便地进行垃圾回收。与此相似,整型常量池也...
### Java Class 文件中的常量池类型分类 在Java中,每个`.class`文件都包含一个常量池(Constant Pool),它是一个特殊的数据结构,用于存储类或接口的编译期常量,包括直接引用到其他类、字段和方法的信息。常量池...
Java class文件格式之常量池 Java class文件格式之常量池是Java虚拟机(JVM)加载和执行Java类文件的核心组件之一。常量池是class文件的一部分,存储着Java类文件中的各种常量信息,如字符串常量、类名、方法名、...
1、举例说明 变量 常量 字面... 静态常量池:*.class文件中的常量池,class文件中的常量池不仅仅包含字符串,数值字面量,还包含类、方法的信息,占用class文件绝大部分空间。 运行时常量池:是jvm虚拟机在完成类装
3. **常量池**:常量池是Class文件中一个非常重要的部分,用于存放各种字面量和符号引用,如类和接口的全限定名、字段的名称和描述符、方法的名称和描述符等。常量池采用数组形式存储,并且每个元素的类型是通过首...
- 类加载过程中,会把.class文件中的常量池内容复制到方法区的常量池中。 - 方法区的内存回收主要针对常量池。 - **应用场景**: - 字符串字面量的存储。 - 方法、字段的符号引用。 #### 实例解析 下面通过几...
Class文件中的常量池对于理解Java类的结构至关重要,它不仅有助于解释器解析代码,还能帮助开发者调试和理解类的内部结构。 #### 运行时常量池 运行时常量池是在类被加载到JVM中时创建的。当类被加载时,其对应的`...
《使用jclasslib修改Java Class文件内容》 在Java编程世界中,编译后的类文件(.class)是程序的基础,它们包含了字节码指令,是JVM运行时的直接执行对象。然而,通常情况下,我们并不直接操作这些类文件,而是通过...
另外,`javap`命令可以显示`.class`文件的详细信息,包括公共方法、常量池等。 7. **优化与JIT编译**: JVM的Just-In-Time (JIT) 编译器可以在运行时将经常执行的热点代码编译成本地机器代码,以提高性能。HotSpot...
#### 二、Class文件主要内容解析 1. **Magic Number (魔数)** - 魔数是Class文件的前四个字节,值为`0xCAFEBABE`。它的主要功能是标识该文件为合法的Class文件,便于JVM快速识别和加载。 2. **Version Numbers ...
安装并运行该工具后,可以打开并查看Class文件的详细内容,包括类结构、字节码、常量池等。 下载说明.txt可能包含了获取和安装jclasslib的详细步骤,而新云软件.url可能是指向该工具下载页面的快捷方式。 总之,...
Java Class文件遵循特定的文件格式,这个格式由一系列的8位字节构成,包括魔数(Magic Number)、版本信息、常量池、访问标志、类和父类索引、接口索引集合、字段表集合、方法表集合、属性表集合等。这些结构共同...
运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量...
常量池静态常量池即*.class文件中的常量池,用于存放字面量和符号引用运行时常量池是jvm运行期间,存储常量的数据结构运行时常量池概念运行时常量池(Runti
Class文件是Java编译器将源代码编译后的结果,包含了类的结构信息、方法定义、常量池等关键数据。理解并能解析Class文件,对于进行JVM优化、字节码分析、动态代理、插桩等高级技术至关重要。 首先,Class文件是以二...
1. 常量池:常量池是Class文件中占用空间最大的部分,包含各种字面量(如字符串、整型常量)和符号引用(如类名、字段名、方法名)。常量池的每一个条目都有特定的类型,如CONSTANT_Utf8_info表示字符串,CONSTANT_...
它可以显示类的结构,包括常量池、字段、方法、指令等,并允许用户添加、删除或修改这些元素。 3. **字节码编辑**:通过 JBE,开发者可以直接编辑字节码指令,这在处理性能优化、加密、混淆或调试时特别有用。它也...
在Java应用程序运行时,Java虚拟机会保存一份内部的运行时常量池,它区别于class文件的常量池,是class文件常量池映射到虚拟机中的数据结构。 关于class文件常量池的部分可以参考之前的博文实例探索Class文件。 1...