Java中的常量池
JVM中有:
Class文件常量池、运行时常量池、全局字符串常量池、基本类型包装类对象 常量池
Class文件常量池:
package basics;
public class ConstanPoolTest {
private int value = 1;
public String s = "abc";
public final static int f = 0x101;
public void setValue(int v) {
final int temp = 3;
this.value = temp + v;
}
public int getValue() {
return value;
}
}
"D:\Program Files\Java\jdk1.8.0_202\bin\javap.exe" -v basics.ConstanPoolTest
Classfile /D:/QFWorkspace/IdeaProjects/JavaReview/target/classes/basics/ConstanPoolTest.class
Last modified 2019-8-4; size 627 bytes
MD5 checksum bb29ca138910d931e8f2c777f6abb41b
Compiled from "ConstanPoolTest.java"
public class basics.ConstanPoolTest
minor version: 0
major version: 49
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#29 // java/lang/Object."<init>":()V
#2 = Fieldref #5.#30 // basics/ConstanPoolTest.value:I
#3 = String #31 // abc
#4 = Fieldref #5.#32 // basics/ConstanPoolTest.s:Ljava/lang/String;
#5 = Class #33 // basics/ConstanPoolTest
#6 = Class #34 // java/lang/Object
#7 = Utf8 value
#8 = Utf8 I
#9 = Utf8 s
#10 = Utf8 Ljava/lang/String;
#11 = Utf8 f
#12 = Utf8 ConstantValue
#13 = Integer 257
#14 = Utf8 <init>
#15 = Utf8 ()V
#16 = Utf8 Code
#17 = Utf8 LineNumberTable
#18 = Utf8 LocalVariableTable
#19 = Utf8 this
#20 = Utf8 Lbasics/ConstanPoolTest;
#21 = Utf8 setValue
#22 = Utf8 (I)V
#23 = Utf8 v
#24 = Utf8 temp
#25 = Utf8 getValue
#26 = Utf8 ()I
#27 = Utf8 SourceFile
#28 = Utf8 ConstanPoolTest.java
#29 = NameAndType #14:#15 // "<init>":()V
#30 = NameAndType #7:#8 // value:I
#31 = Utf8 abc
#32 = NameAndType #9:#10 // s:Ljava/lang/String;
#33 = Utf8 basics/ConstanPoolTest
#34 = Utf8 java/lang/Object
{
public java.lang.String s;
descriptor: Ljava/lang/String;
flags: ACC_PUBLIC public static final int f;
descriptor: I
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: int 257 public basics.ConstanPoolTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: putfield #2 // Field value:I
9: aload_0
10: ldc #3 // String abc
12: putfield #4 // Field s:Ljava/lang/String;
15: return
LineNumberTable:
line 3: 0
line 4: 4
line 5: 9
LocalVariableTable:
Start Length Slot Name Signature
0 16 0 this Lbasics/ConstanPoolTest; public void setValue(int);
descriptor: (I)V
flags: ACC_PUBLIC
Code:
stack=3, locals=3, args_size=2
0: iconst_3
1: istore_2
2: aload_0
3: iconst_3
4: iload_1
5: iadd
6: putfield #2 // Field value:I
9: return
LineNumberTable:
line 9: 0
line 10: 2
line 11: 9
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this Lbasics/ConstanPoolTest;
0 10 1 v I
2 8 2 temp I public int getValue();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field value:I
4: ireturn
LineNumberTable:
line 14: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lbasics/ConstanPoolTest;
}
SourceFile: "ConstanPoolTest.java" Process finished with exit code 0
可以看到该class文件的版本号、常量池、已经编译后的字节码。既然是常量池,那么其中存放的肯定是常量,那么什么是“常量”呢? class文件常量池主要存放两大常量:字面量和符号引用
字面量: 字面量接近java语言层面的常量概念,主要包括:
- 文本字符串,也就是我们经常申明的: public String s = "abc";中的"abc"
- 用final修饰的成员变量,包括静态变量、实例变量和局部变量
注:上面说的存在于常量池的字面量,指的是数据的值,也就是abc和0x101(257),通过上面对常量池的观察可知这两个字面量是确实存在于常量池的。
而对于基本类型数据(甚至是方法中的局部变量),也就是上面的private int value = 1;常量池中只保留了他的的字段描述符I和字段的名称value,他们的字面量不会存在于常量池
2). 符号引用
符号引用主要设涉及编译原理方面的概念,包括下面三类常量:
- 类和接口的全限定名,也就是Ljava/lang/String;这样,将类名中原来的"."替换为"/"得到的,主要用于在运行时解析得到类的直接引用,像上面
#5 = Class #33 // JavaBasicKnowledge/JavaBean
#33 = Utf8 JavaBasicKnowledge/JavaBean
- 字段的名称和描述符,字段也就是类或者接口中声明的变量,包括类级别变量和实例级的变量
#4 = Fieldref #5.#32 // JavaBasicKnowledge/JavaBean.value:I
#5 = Class #33 // JavaBasicKnowledge/JavaBean
#32 = NameAndType #7:#8 // value:I #7 = Utf8 value
#8 = Utf8 I
//这两个是局部变量,值保留字段名称
#23 = Utf8 v
#24 = Utf8 temp
可以看到,对于方法中的局部变量名,class文件的常量池仅仅保存字段名。
- 方法中的名称和描述符,也即参数类型+返回值
#21 = Utf8 setValue
#22 = Utf8 (I)V #25 = Utf8 getValue
#26 = Utf8 ()I
运行时常量池
运行时常量池是方法区的一部分,所以也是全局贡献的,我们知道,jvm在执行某个类的时候,必须经过加载、链接(验证、准备、解析)、初始化,在第一步加载的时候需要完成:
- 通过一个类的全限定名来获取此类的二进制字节流
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
- 在内存中生成一个类对象,代表加载的这个类,这个对象是java.lang.Class,它作为方法区这个类的各种数据访问的入口。
类对象和普通对象是不同的,类对象是在类加载的时候完成的,是jvm创建的并且是单例的,作为这个类和外界交互的入口, 而普通的对象一般是在调用new之后创建。
上面的第二条,将class字节流代表的静态存储结构转化为方法区的运行时数据结构,其中就包含了class文件常量池进入运行时常量池的过程,这里需要强调一下不同的类共用一个运行时常量池,同时在进入运行时常量池的过程中,多个class文件中常量池中相同的字符串只会存在一份在运行时常量池,这也是一种优化。
运行时常量池的作用是存储java class文件常量池中的符号信息,运行时常量池中保存着一些class文件中描述的符号引用,同时在类的解析阶段还会将这些符号引用翻译出直接引用(直接指向实例对象的指针,内存地址),翻译出来的直接引用也是存储在运行时常量池中。
运行时常量池相对于class常量池一大特征就是具有动态性,java规范并不要求常量只能在编译时才产生,也就是说运行时常量池的内容并不全部来自class常量池,在运行时可以通过代码生成常量并将其放入运行时常量池中,这种特性被用的最多的就是String.intern()
Java中的常量池的更多相关文章
- 【Java_基础】java中的常量池
1.java常量池的介绍 java中的常量池,通常指的是运行时常量池,它是方法区的一部分,一个jvm实例只有一个运行常量池,各线程间共享该运行常量池. java常量池简介:java常量池中保存了一份在 ...
- java中Integer常量池
我们先看一个关于Integer的例子 public static void main(String[] args) { // TeODO Auto-generated method stu Integ ...
- Java中的常量池(字符串常量池、class常量池和运行时常量池)
转载. https://blog.csdn.net/zm13007310400/article/details/77534349 简介: 这几天在看Java虚拟机方面的知识时,看到了有几种不同常量池的 ...
- 19、java内存分配 常量池详解
在class文件中,“常量池”是最复杂也最值得关注的内容. Java是一种动态连接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int.long等等)和对象型(如Stri ...
- 【万字图文-原创】 | 学会Java中的线程池,这一篇也许就够了!
碎碎念 关于JDK源码相关的文章这已经是第四篇了,原创不易,粉丝从几十人到昨天的666人,真的很感谢之前帮我转发文章的一些朋友们. 从16年开始写技术文章,到现在博客园已经发表了222篇文章,大多数都 ...
- Java字面常量与常量池
Java中的字面常量(区别于final创建的有名常量)通常会保存在常量池中,常量池可以理解为像堆一样的内存区域.但是常量池有一个特性就是,如果常量池中已存在该常量将不会再次为该常量开辟内存 还是看个程 ...
- jdk1.7中的常量池
在探究jdk1.7中的常量池,我们可以先看看以下的这段代码 public static void main(String[] args) throws Throwable { List<Stri ...
- 第46节:Java当中的常量池
Java当中的常量池 在Java虚拟机jvm中,内存分布为:虚拟机堆,程序计数器,本地方法栈,虚拟机栈,方法区. 程序计数器是jvm执行程序的流水线,是用来存放一些指令的,本地方法栈是jvm操作系统方 ...
- 关于jvm中的常量池和String.intern()理解
1. 首先String不属于8种基本数据类型,String是一个对象. 因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ne ...
随机推荐
- 两种接口传送数据协议(xml和json)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/tianyazaiheruan/article/details/37659983 规范性接口开发 ...
- VisualStuido中将C#脚本封装打包DLL并调用
DLL (Dynamic Link Library)---动态链接库 首先了解下使用DLL的优势,程序运行时不用加载所有代码,只有运行到引用时,才从DLL库中取出.并且使用DLL文件还可以减小程序体积 ...
- python接口自动化(delete请求)
python接口自动化(delete请求) 一.delete请求的目的:删除资源 二.应用 导包:import requests 调用delete方法:requests.delete(url) 获取响 ...
- java堆转储与内存分析
jmap -dump:format=b,file=dumpfile.hprof pid 将进程的堆转储到dumpfile.hprof文件里 jmap -heap pid 查看堆内存占用情 ...
- Storm设计思想
- wbinfo - 向winbind服务查询信息
总览 SYNOPSIS wbinfo [-a user%password] [-c username] [-C groupname] [--domain domain] [-I ip] [-s sid ...
- python基础小点
变量的命名规则 由字母.下划线.数字组成,且不能以数字开头 不能用关键字作为变量名 最好不要与python内置的一些方法和类名冲突 变量名应尽量简短且具有意义,多个单词之间用下划线连接 注释 # - ...
- js排他功能示例
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- Eclipse+Marven + spring mvc 新建一个 Hello world 项目
1. 打开Eclipse,菜单 File->New->Marven Project. 2. 点击 Next, 3. 选择 marv ...
- vue组件添加鼠标滚动事件
在一个组件标签上加鼠标滚动事件,应该写成 @mousewheel.native