我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java常量池详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java常量池详解

java中有几种不同的常量池,以下的内容是对java中几种常量池的介绍,其中最常见的就是字符串常量池。

(1)class常量池

在Java中,Java类被编译后就会形成一份class文件;class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,用于存放编译器生成的各种字面量和符号引用,每个class文件都有一个class常量池。

其中字面量包括:1.文本字符串 2.八种基本类型的值 3.被声明为final的常量等;

符号引用包括:1.类和方法的全限定名 2.字段的名称和描述符 3.方法的名称和描述符。

(2)运行时常量池

运行时常量池存在于内存中,也就是class常量池被加载到内存之后的版本,是方法区的一部分(JDK1.8 运行时常量池在元空间,元空间也是方法区的一种实现)。不同之处是:它的字面量可以动态的添加(String类的intern()),符号引用可以被解析为直接引用。

JVM在执行某个类的时候,必须经过加载、连接、初始化,而连接又包括验证、准备、解析三个阶段。而当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中,这里所说的常量包括:基本类型包装类(包装类不管理浮点型,整形只会管理-128到127)和字符串类型(即通过String.intern()方法可以强制将String放入常量池),运行时常量池是每个类私有的。在解析阶段,会把符号引用替换为直接引用。

(3)基本类型包装类常量池

Java 基本类型的包装类的大部分都实现了常量池技术。Byte,Short,Integer,Long这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character创建了数值在[0,127]范围的缓存数据,Boolean直接返回True或False,如果超出对应范围就会去创建新的对象。两种浮点数类型的包装类Float,Double并没有实现常量池技术。

Integer 缓存源码:



public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
      return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];
}

举个栗子:


Integer i1 = 40;
  Integer i2 = 40;
  Integer i3 = 0;
  Integer i4 = new Integer(40);
  Integer i5 = new Integer(40);
  Integer i6 = new Integer(0);
  System.out.println("i1=i2   " + (i1 == i2));
  System.out.println("i1=i2+i3   " + (i1 == i2 + i3));
  System.out.println("i1=i4   " + (i1 == i4));
  System.out.println("i4=i5   " + (i4 == i5));
  System.out.println("i4=i5+i6   " + (i4 == i5 + i6));   
  System.out.println("40=i5+i6   " + (40 == i5 + i6));

结果:

i1=i2         true
i1=i2+i3   true
i1=i4        false
i4=i5        false
i4=i5+i6   true
40=i5+i6   true

解释:1-4语句结果应该很显然,因为Integer i1=40 这一行代码会发生装箱,也就是说这行代码等价于 Integer i1=Integer.valueOf(40),Integer.valueOf()方法基于减少对象创建次数和节省内存的考虑,缓存了[-128,127]之间的数字,如果在此数字范围内直接返回缓存中的对象。在此之外,直接new出来,显然40在常量池的缓存[-128,127]范围内;因此,i1 直接使用的是常量池中的对象。而Integer i1 = new Integer(40) 会直接创建新的对象;语句 i4 == i5 + i6,因为+这个操作符不适用于 Integer 对象,首先 i5 和 i6 进行自动拆箱操作,进行数值相加,即 i4 == 40。然后 Integer 对象无法与数值进行直接比较,所以 i4 自动拆箱转为 int 值 40,最终这条语句转为 40 == 40 进行数值比较,所以结果为true。第六条语句同理。

额外说明:所有整型包装类对象之间值的比较,全部使用 equals 方法比较。

对于Integer var = ?在-128至127之间的赋值,Integer对象是在 IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,推荐使用equals方法进行判断。

(4)字符串常量池

在JDK1.6及之前版本,字符串常量池存放在方法区中的,在JDK1.7版本以后,字符串常量池被移到了堆中了。

HotSpot VM里,记录interned string的一个全局表叫做StringTable,它本质上就是个HashSet<String>;这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。

注意:它只存储对java.lang.String实例的引用,而不存储String对象的内容

字符串常量池和上面的基本类型包装类常量池有些不同,字符串常量池中没有事先缓存一些数据,而是如果要创建的字符串在常量池内存在就返回对象的引用,如果不存在就创建一个放在常量池中;

在Java中,有两种创建字符串对象的方法,一种是字面量直接创建,另一种是new一个String对象,这两种方法创建字符串对象的过程会不一样;


(1)String str = "abc";
(2)String str = new String("abc");

如果是第一种方式创建对象,因为是字面量直接创建,所以在编译的时候是确定的,如果该字符串不在常量池中会将该字符串放入常量池中并返回字符串对象的引用,如果在常量池中直接返回字符串对象的引用,如果是第二种方式创建对象,因为要创建String类型的对象,String对象是在运行时才加载到内存的堆中的,属于运行时创建,所以要先在堆中创建一个String对象,再去常量池中寻找是否有相同的字符串,如果有就返回堆中Sring对象的引用,如果没有则在将该字符串加入常量池中。

举个栗子:

比较下列两种创建字符串的方法:

String str1 = new String("abc");

String str2 = "abc";

答案:第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 运行时期创建 。

第二种是先在栈中创建一个对String类的对象引用变量str2,然后通过符号引用去字符串常量池里找有没有”abc”,如果没有,则将”abc”存放进字符串常量池,并令str2指向”abc”,如果已经有”abc” 则直接令str2指向“abc”。“abc”存于常量池在 编译期间完成 。

String s = new String("abc")
这条语句创建了几个对象?

答案:共2个。第一个对象是”abc”字符串存储在常量池中,第二个对象在Java Heap中的 String 对象。这里不要混淆了s是放在栈里面的指向了Heap堆中的String对象。

String s1 = new String("s1") ;

String s1 = new String("s1") ;

上面一共创建了几个对象?

答案:3个 ,编译期常量池中创建1个,运行期堆中创建2个.(用new创建的每new一次就在堆上创建一个对象,用引号创建的如果在常量池中已有就直接指向,不用创建)

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java常量池详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

java常量池图文详解

java常量池是一个经久不衰的话题,也是面试官的最爱,题目花样百出,小菜早就对常量池有所耳闻,这次好好总结一下。推荐:java视频教程jvm虚拟内存分布:程序计数器是jvm执行程序的流水线,存放一些跳转指令,这个太高深,小菜不懂。本地方法栈是jvm调用操作系统
java常量池图文详解
2016-07-05

Java 常量池的实例详解

Java 常量池的实例详解Java的常量池中包含了类、接口、方法、字符串等一系列常量值。常量池在编译期间就已经确定,并保存在*.class文件中一、对于相同的常量值,常量池中只保存一份拷贝。而且,当一个字符串由多个字符串常量链接而成时,多个
2023-05-31

深入探索Java常量池

Java的常量池通常分为两种:静态常量池和运行时常量池静态常量池:class文件中的常量池,class文件中的常量池包括了字符串(数字)字面值,类和方法的信息,占用了class文件的大部分空间。运行时常量池:JVM在完成加载类之后将clas
2023-05-30

如何解析Java常量池与字符串intern

这期内容当中小编将会给大家带来有关如何解析Java常量池与字符串intern,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。在Java应用程序运行时,Java虚拟机会保存一份内部的运行时常量池,它区别于cl
2023-06-17

Java中的堆、栈和常量池怎么理解

这篇文章主要讲解了“Java中的堆、栈和常量池怎么理解”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中的堆、栈和常量池怎么理解”吧!1.寄存器最快的存储区, 由编译器根据需求进行分配
2023-06-17

java线程池详解

线程池概述1. 线程池就是一个管理线程的池子,可以降低创建和销毁线程带来的资源消耗因为线程其实也是一个对象,创建一个对象,需要经过类加载过程,销毁一个对象,需要走GC垃圾回收流程,都是需要资源开销的。2. 提高响应速度,任务到达了相对于从线程池取线程,自己创建
java线程池详解
2015-04-06

Java常量池面试题的示例分析

这篇文章主要介绍Java常量池面试题的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!今天My partner问我一个让他头疼的Java question,求输出结果:/** * * @author Dr
2023-06-17

详解Java 虚拟机(第④篇)——8 种基本类型的包装类和常量池

Java 基本类型的包装类的大部分都实现了常量池技术, 即Byte,Short,Integer,Long,Character,Boolean; 这 5 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据, 但是超出此范围仍然
2023-06-05

如何理解Java 虚拟机中的String 类和常量池

本篇文章为大家展示了如何理解Java 虚拟机中的String 类和常量池,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、String 对象的两种创建方式String str1 = "abcd";S
2023-06-05

详解Java枚举与接口常量和类常量的区别

这篇文章主要为大家详细介绍了Java中枚举与接口常量、类常量有什么区别,文中的示例代码讲解详细,具有一定的参考价值,感兴趣的可以了解一下
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录