
作为最基本的参考数据类型,Java设计人员为String提供了String常量池以提高其性能,那么字符串常量池的具体原理是什么,我们采取以下三个问题来理解字符串Constant pool:
1. 字符串常量池的设计意图是什么?
2. 字符串常量池在哪里?
3. 如何操作字符串常量池?
字符串常量池的设计思想
1. 像其他对象分配一样,字符串的分配消耗大量的时间和空间成本. 作为最基本的数据类型,大量频繁创建的字符串极大地影响了程序的性能.
2. 为了提高性能并减少内存开销,JVM在实例化字符串常量时进行了一些优化.
1)与缓存区类似,为字符串打开一个字符串常量池.
2)创建字符串常量时,首先要坚持字符串是否存在于字符串常量池中.
3)如果字符串存在,则返回引用实例. 如果不存在,请实例化该字符串并将其放入池中.
3. 实施依据
1)这种优化的基础是因为字符串是不可变的,因此您可以共享它而不必担心数据冲突.
2)在运行时实例创建的全局字符串常量池中有一个表,该表始终为该池中的每个唯一字符串对象维护一个引用string池,这意味着它们始终引用字符串常量池对象,因此这些常量池中的字符串将不会被垃圾收集器收集.
代码: 从字符串常量池中获取相应的字符串


字符串常量池在哪里
在分析字符串常量池的位置时,首先要了解堆,堆栈和方法区域:

1,堆
1)存储对象,每个对象包含一个对应的类.
2)JVM只有一个由所有线程共享的堆. 堆不存储基本类型和对象引用,仅存储对象本身.
3)对象是由垃圾收集器收集的,因此不需要确定大小和生命周期.
2. 堆叠
1)每个线程都包含一个堆栈区域,并且只有基本数据类型的对象和自定义对象的引用(不是对象)存储在堆栈中.
2)每个堆栈中的数据(原始类型和对象引用)都是私有的.
3)堆栈分为三个部分: 基本类型变量区,执行环境上下文和操作指令区(存储操作指令).
4)可以确定数据大小和生命周期. 如果没有引用数据,数据将自动消失.
3. 方法区域
1)静态区域(如堆)由所有线程共享.
2)方法区域包含整个程序中始终唯一的元素,例如类和静态变量.

方法区域中存在字符串常量池
代码: 将字符串存储在堆栈方法区域


创建字符串对象
面试问题: String str4 = new String(“ abc”)创建了多少个对象?
1. 检查常量池中是否存在“ abc”对象.
1)如果是,则返回相应的引用实例;
2)如果不是,则创建一个相应的实例对象.
2. 在堆中新建一个String(“ abc”)对象.
3. 将对象地址分配给str4并创建引用.
因此,如果常量池中没有“ abc”文字,则将创建两个对象,否则将创建一个对象并创建一个引用.
根据字面量,经常会提出这样的变体问题:
String str1 = new String(“ A” +“ B”);将创建多少个对象?
String str2 = new String(“ ABC”)+“ ABC”;将创建多少个对象?

str1:
字符串常量池: “ A”,“ B”,“ AB”: 3
堆: new String(“ AB”): 1
报价: str1: 1
总计: 5
str2:
字符串常量池: “ ABC”: 1
堆: new String(“ ABC”): 1
引用: str2: 1
总计: 3
代码: 变量和常量的基本类型,变量和引用存储在堆栈中,而常量存储在常量池中.


如何操作字符串常量池
1. 当JVM实例化字符串常量池时


2. String.intern()
由new运算符创建的字符串对象不会指向字符串池中的任何对象,但是您可以使用字符串的intern()方法指向其中之一. java.lang.String.intern()返回保留的池字符串,它是全局字符串池中的一项. 如果以前不在全局字符串池中,则将其添加到其中.

补充: 文字和常量池的初步研究
字符串对象是使用字符数组在内部存储的,因此请看以下示例:

1. 将分配一个11个长度的char数组,并在常量池中分配一个由该char数组组成的字符串,然后m将引用该字符串.
2. 使用n引用常量池中的字符串,因此它与n引用相同的对象.
3. 生成一个新的字符串,但是内部字符数组引用m中的字符数组.
4. 也将生成一个新的字符串,但是内部字符数组是指常量池中字符串内部的字符数组,这意味着它与u相同.
如果使用图表来表示,则情况可能是这样的(使用虚线仅表示两者之间没有特殊关系):

测试演示:

结论:
1string池,m和n是同一对象;
2,m,u,v是不同的对象;
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-239282-1.html
都是这样的状态
最后面的那个手势和表情