方法区和常量池
方法区和常量池
最近一直被方法区里面存着什么东西困扰着?
1. 方法区里存 class 文件信息和 class 文件常量池是个什么关系。
2.class 文件常量池和运行时常量池是什么关系。
方法区存着类的信息,常量和静态变量,即类被编译后的数据。这个说法其实是没问题的,只是太笼统了。更加详细一点的说法是方法区里存放着类的版本,字段,方法,接口和常量池。常量池里存储着字面量和符号引用。
符号引用包括:1. 类的全限定名,2. 字段名和属性,3. 方法名和属性。
下面一张图是我画的方法区,class 文件信息,class 文件常量池和运行时常量池的关系
下面一张图用来表示方法区 class 文件信息包括哪些内容:
可以看到在方法区里的 class 文件信息包括:魔数,版本号,常量池,类,父类和接口数组,字段,方法等信息,其实类里面又包括字段和方法的信息。
下面的图表是 class 文件中存储的数据类型
| 类型 | 名称 | 数量 |
|---|---|---|
| u4 | magic | 1 |
| u2 | minor_version | 1 |
| u2 | major_version | 1 |
| u2 | constant_pool_count | 1 |
| cp_info | constant_pool | constant_pool_count - 1 |
| u2 | access_flags | 1 |
| u2 | this_class | 1 |
| u2 | super_class | 1 |
| u2 | interfaces_count | 1 |
| u2 | interfaces | interfaces_count |
| u2 | fields_count | 1 |
| field_info | fields | fields_count |
| u2 | methods_count | 1 |
| method_info | methods | methods_count |
| u2 | attribute_count | 1 |
| attribute_info | attributes | attributes_count |
下面用一张图来表示常量池里存储的内容:
用一个 class 文件实际反编译一下
下面是原 java 代码
public class TestInt {
private String str = "hello";
void printInt(){
System.out.println(65535);
}
}
经过反编译后获得 class 文件是下面这样的
可以看出被反编译的 class 文件中的内容和上面所说的是能对应上的。这就解答了 class 文件和静态常量池(class 文件常量池)的关系
静态常量池和动态常量池的关系以及区别
静态常量池存储的是当 class 文件被 java 虚拟机加载进来后存放在方法区的一些字面量和符号引用,字面量包括字符串,基本类型的常量,符号引用其实引用的就是常量池里面的字符串,但符号引用不是直接存储字符串,而是存储字符串在常量池里的索引。(因为都是类和结构的全限定名称、方法和字段的名称、描述符,所以都是字符串,引用存储的是索引,虽然它们都在常量池中)
动态常量池是当 class 文件被加载完成后,java 虚拟机会将静态常量池里的内容转移到动态常量池里,在静态常量池的符号引用有一部分是会被转变为直接引用的,比如说类的静态方法或私有方法,实例构造方法,父类方法,这是因为这些方法不能被重写其他版本,所以能在加载的时候就可以将符号引用转变为直接引用,而其他的一些方法是在这个方法被第一次调用的时候才会将符号引用转变为直接引用的。
总结:
方法区里存储着 class 文件的信息和动态常量池, class 文件的信息包括类信息和静态常量池。可以将类的信息是对 class 文件内容的一个框架,里面具体的内容通过常量池来存储。
动态常量池里的内容除了是静态常量池里的内容外,还将静态常量池里的符号引用转变为直接引用,而且动态常量池里的内容是能动态添加的。例如调用 String 的 intern 方法就能将 string 的值添加到 String 常量池中,这里 String 常量池是包含在动态常量池里的,但在 jdk1.8 后,将 String 常量池放到了堆中。
下面有一篇文章写的是比较好的
http://blog.csdn.net/vegetable_bird_001/article/details/51278339

浙公网安备 33010602011771号