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 ...
随机推荐
- VScode Python no module的解决方法
在lauch.json中,修改 "env": {}为 "env": {"PYTHONPATH":"${workspaceRoot} ...
- 2-数据分析-matplotlib-1-概述
1.matplotlib: 最流行的Python底层绘图库,主要做数据可视化图表,名字取材于MATLAB,模仿MATLAB构建. 2.学习matplotlib的意义: (1)能将数据进行可视化,更直观 ...
- Unity Shader后处理-搜索灰度效果
如U3D中Hierarchy面板下的搜索效果: 讲解分析: 1.这种PostEffect效果其实就是指Unity shader的后处理,即游戏中实现屏幕特效的常见方法.顾名思义屏幕后处理就是指在渲染完 ...
- 自定义可点击的ImageSpan并在TextView中内置“View“
有的时候可能想在TextView中添加一些图片,比如下图,发短信输入联系人时,要把联系人号码换成一个图片,但这个图片无法用固定的某张图,而是根据内容进行定制的,这更像一个view. 当然,如果你不是v ...
- 本地调试H5页面
摘要 详细讲述微信H5页面调试(安装在安卓或iOS手机上的),钉钉内H5页面的调试,QQ.微博以及各浏览器上H5页面的调试方法 背景 大学毕业快要一年了,用leader的话说我也是有一年开发经验的前端 ...
- 使用cpanel后台的“时钟守护作业”功能完成空间的定时全备份
现在不少虚拟主机都是使用的cpanel控制面板,由于空间商选用的cpanel版本不同,有的带有定时备份功能,而有的就没有这项功能,需要手动备份.不过,还在绝大部分的cpanel后台都有“时钟守护作业” ...
- 2019-7-15-WPF-测试触摸设备发送触摸按下和抬起不成对
title author date CreateTime categories WPF 测试触摸设备发送触摸按下和抬起不成对 lindexi 2019-7-15 9:3:51 +0800 2019-0 ...
- 小波变换C代码
#include <stdio.h> #include <stdlib.h> #define LENGTH 512//信号长度 /*********************** ...
- VS2017编译Qt x64
1.打开VS本机工具命令提示vcvars64.bat. 2.进入Qt源码目录 cd E:\qt-everywhere-opensource-src- mkdir qt-build && ...
- 自定义Java annotation
1.目录结构: 2.pom文件: Simple exmple: package com.yuan.simple; import java.lang.annotation.Retention; impo ...