Java String:字符串常量池(转)
作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么?
字符串常量池的设计思想是什么?
字符串常量池在哪里?
如何操作字符串常量池?
字符串常量池的设计思想
字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能
JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化
为字符串开辟一个字符串常量池,类似于缓存区
创建字符串常量时,首先坚持字符串常量池是否存在该字符串,存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中
实现的基础
实现该优化的基础是因为字符串是不可变的,可以不用担心数据冲突进行共享
运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收
代码:从字符串常量池中获取相应的字符串
String str1 = “hello”;
String str2 = “hello”; System.out.printl("str1 == str2" : str1 == str2 ) //true
字符串常量池在哪里
在分析字符串常量池的位置时,首先了解一下堆、栈、方法区:


堆
存储的是对象,每个对象都包含一个与之对应的class
JVM只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定
栈
每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象)
每个栈中的数据(原始类型和对象引用)都是私有的
栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)
数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失
方法区
静态区,跟堆一样,被所有的线程共享
方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量
字符串常量池则存在于方法区
代码:堆栈方法区存储字符串
String str1 = “abc”;
String str2 = “abc”;
String str3 = “abc”;
String str4 = new String(“abc”);
String str5 = new String(“abc”);

字符串对象的创建
面试题:String str4 = new String(“abc”) 创建多少个对象?
在常量池中查找是否有“abc”对象
有则返回对应的引用实例
没有则创建对应的实例对象
在堆中 new 一个 String("abc") 对象
将对象地址赋值给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个
代码:基础类型的变量和常量,变量和引用存储在栈中,常量存储在常量池中
int a1 = 1;
int a2 = 1;
int a3 = 1;
public static int INT1 =1 ;
public static int INT2 =1 ;
public static int INT3 =1 ;

操作字符串常量池的方式
JVM实例化字符串常量池时
String str1 = “hello”;
String str2 = “hello”; System.out.printl("str1 == str2" : str1 == str2 ) //true
String.intern()
- 当调用 intern() 方法时,编译器会将字符串添加到常量池中(stringTable维护),并返回指向该常量的引用。


// Create three strings in three different ways.
String s1 = "Hello";
String s2 = new StringBuffer("He").append("llo").toString();
String s3 = s2.intern(); // Determine which strings are equivalent using the ==
// operator
System.out.println("s1 == s2? " + (s1 == s2)); // false
System.out.println("s1 == s3? " + (s1 == s3)); // true
字面量可以理解为实际值,int a = 8中的8和String a = "hello"中的hello都是字面量
符号引用就是一个字符串,只要我们在代码中引用了一个非字面量的东西,不管它是变量还是常量,它都只是由一个字符串定义的符号,这个字符串存在常量池里,类加载的时候第一次加载到这个符号时,就会将这个符号引用(字符串)解析成直接引用(指针)
补充:字面量和常量池初探
字符串对象内部是用字符数组存储的,那么看下面的例子:
String m = "hello,world";
String n = "hello,world";
String u = new String(m);
String v = new String("hello,world");
会分配一个11长度的char数组,并在常量池分配一个由这个char数组组成的字符串,然后由m去引用这个字符串
用n去引用常量池里边的字符串,所以和m引用的是同一个对象
生成一个新的字符串,但内部的字符数组引用着m内部的字符数组
同样会生成一个新的字符串,但内部的字符数组引用常量池里边的字符串内部的字符数组,意思是和u是同样的字符数组
使用图来表示的话,情况就大概是这样的(使用虚线只是表示两者其实没什么特别的关系):

测试demo:
String m = "hello,world";
String n = "hello,world";
String u = new String(m);
String v = new String("hello,world"); System.out.println(m == n); //true
System.out.println(m == u); //false
System.out.println(m == v); //false
System.out.println(u == v); //false
结论:
m和n是同一个对象
m,u,v都是不同的对象
m,n,u,v但都使用了同样的字符数组,并且用equal判断的话也会返回true
Java String:字符串常量池(转)的更多相关文章
- 讲一讲Java的字符串常量池,看完你的思路就清晰了
前言 很多朋友Java的字符串常量池的概念困扰了很长一段时间,最近研究了一下jvm指令码,终于对它有了大概的了解. 在展示案例前,我们需要先搞清楚一个概念,众所周知,jvm的内存模型由程序计数器.虚拟 ...
- Java中String字符串常量池总结
最近到广州某建站互联网公司面试,当时面试官问假设有两个字符串String a="abc",String b = "abc";问输出a==b是true还是fals ...
- Java中String字符串常量池
首先看一个例子,通过这个例子更能快速理解String常量池 public static void main(String[] args) { String a = "ab"; St ...
- string字符串常量池在内存中的位置
这里仅仅是举个简单的样例说明字符串常量池在内存中的位置. 闲言少叙,直接上代码. <span style="font-size: large;">import java ...
- String字符串常量池简介
直接贴代码---> public class Test { public static void main(String[] args) { /** * 为了提升字符串的访问效率,在程序中使用了 ...
- Java String类相关知识梳理(含字符串常量池(String Pool)知识)
目录 1. String类是什么 1.1 定义 1.2 类结构 1.3 所在的包 2. String类的底层数据结构 3. 关于 intern() 方法(重点) 3.1 作用 3.2 字符串常量池(S ...
- [JAVA]字符串常量池String pool
字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定.不仅如此,还可以使用 String 的 intern() 方法在运行过程中将 ...
- Java中,那些关于String和字符串常量池你不得不知道的东西
老套的笔试题 在一些老套的笔试题中,会要你判断s1==s2为false还是true,s1.equals(s2)为false还是true. String s1 = new String("xy ...
- 结合字符串常量池/String.intern()/String Table来谈一下你对java中String的理解
1.字符串常量池 每创建一个字符串常量,JVM会首先检查字符串常量池,如果字符串已经在常量池中存在,那么就返回常量池中的实例引用.如果字符串不在池中,就会实例化一个字符串放到字符串池中.常量池提高了J ...
随机推荐
- 数值格式化 NumberFormat、 DecimalFormat、 RoundingMode
NumberFormat [简介] java.text.NumberFormat extends java.text.Format extends java.lang.Object 实现的接口:Ser ...
- beta版 tomcat 应用监控指标
指标是集合网络搜索得到的汇总并且现在在使用的,现在记录一下 数据平台:Prometheus v2.18.1 展示平台:Grafana 指标来源: 日志类的是mtail 其他都是通过jmx_export ...
- root和sudo
root用户是系统中唯一的超级管理员,它具有等同于操作系统的权限.一些需要root权限的应用,譬如广告阻挡,是需要root权限的.可问题在于root比windows的系统管理员的能力更大,足以把整个系 ...
- java基础——并发1
一.并发的定义 并发:对于这个概念一直就是没怎么搞懂,就是感觉特别的生疏,(自己从从字面上理解就是多个东西,一起出发),所以就上网上查了一些资料: 同时拥有两个或多个线程,如果程序在单核处理器上运行, ...
- 解决github打不开问题
2020.06.22 使用以下方式: 在https://github.com.ipaddress.com/找到: 在https://fastly.net.ipaddress.com/github.gl ...
- 谁再悄咪咪的吃掉异常,我上去就是一 JIO
又到周末了,周更选手申请出站~ 这次分享一下上个月碰到的离奇的问题.一个简单的问题,硬是因为异常被悄咪咪吃掉,过关难度直线提升,导致小黑哥排查一个晚上. 这个美好的晚上,本想着开两把 LOL 无限火力 ...
- 解决 React Native Android:app:validateSigningRelease FAILED 错误
RN 运行的时候报这个错这咋办:
- 02 . Kubeadm部署Kubernetes及简单应用
kubeadm部署Kubernetes kubeadm简介 # kubeadm是一位高中生的作品,他叫Lucas Kaldstrom,芬兰人,17岁用业余时间完成的一个社区项目: # kubeadm的 ...
- python的常用魔法方法详细总结
构造和初始化 __init__我们很熟悉了,它在对象初始化的时候调用,我们一般将它理解为"构造函数". 实际上, 当我们调用x = SomeClass()的时候调用,__init_ ...
- 4. union-find算法
算法的主题思想: 1.优秀的算法因为能够解决实际问题而变得更为重要: 2.高效算法的代码也可以很简单: 3.理解某个实现的性能特点是一个挑战: 4.在解决同一个问题的多种算法之间进行选择时,科学方法是 ...