作者:Seven_Nee

来自:https://segmentfault.com/a/1190000009888357

作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们带着以下三个问题,去理解字符串常量池:

  • 字符串常量池的设计意图是什么?

  • 字符串常量池在哪里?

  • 如何操作字符串常量池?

字符串常量池的设计思想

  1. 字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能

  2. JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化

    • 为字符串开辟一个字符串常量池,类似于缓存区

    • 创建字符串常量时,首先坚持字符串常量池是否存在该字符串

    • 存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中

  1. 实现的基础

    • 实现该优化的基础是因为字符串是不可变的,可以不用担心数据冲突进行共享

    • 运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收

代码:从字符串常量池中获取相应的字符串

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”) 创建多少个对象?

  1. 在常量池中查找是否有“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()

通过new操作符创建的字符串对象不指向字符串池中的任何对象,但是可以通过使用字符串的intern()方法来指向其中的某一个。java.lang.String.intern()返回一个保留池字符串,就是一个在全局字符串池中有了一个入口。如果以前没有在全局字符串池中,那么它就会被添加到里面

// 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 ==// operatorSystem.out.println("s1 == s2? " + (s1 == s2)); // falseSystem.out.println("s1 == s3? " + (s1 == s3)); // true

补充:字面量和常量池初探

字符串对象内部是用字符数组存储的,那么看下面的例子:

String m = "hello,world";String n = "hello,world";String u = new String(m);String v = new String("hello,world");
  1. 会分配一个11长度的char数组,并在常量池分配一个由这个char数组组成的字符串,然后由m去引用这个字符串

  2. 用n去引用常量池里边的字符串,所以和n引用的是同一个对象

  3. 生成一个新的字符串,但内部的字符数组引用着m内部的字符数组

  4. 同样会生成一个新的字符串,但内部的字符数组引用常量池里边的字符串内部的字符数组,意思是和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); //falseSystem.out.println(m == v); //falseSystem.out.println(u == v); //false 

结论:

  • m和n是同一个对象

  • m,u,v都是不同的对象

  • m,u,v,n但都使用了同样的字符数组,并且用equal判断的话也会返回true


●编号1019,输入编号直达本文

●输入m获取文章目录

推荐↓↓↓

Python编程

字符串equal_Java String:字符串常量池相关推荐

  1. String和常量池

    jdk1.6之前常量池属于永久代,jdk1.7以后移到堆中. String s1 = "abc";// 放在常量池中String s2 = "abc";// 从 ...

  2. JavaDay16-P104-P142—二分法查找—String类—常量池—包装—装箱、拆箱—NumberFormatException

    1.二分法查找--建立在数组排序之上 案例程序: class BinarySearch{public static void binarySearch(int[] arr,int des) {Arra ...

  3. 百无聊赖之JavaEE从入门到放弃(十一)string类 常量池原理 内部类

    目录 一.String类和常量池 1.String基础知识 2.常量池 二.内部类 1.概念 2.内部类的作用 3.注意 4.非静态内部类 5.静态内部类 6.匿名内部类 7.局部内部类 一.Stri ...

  4. java equals 字符串_Java String 字符串 比较 == equals

    1.==该运算符表示指向字符串的引用是否相同,如t1==t2这种情况, 是因为在java中字符串的值是不可改变的,相同的字符串在内存中只会存一份, 所以t1和t2指向的是同一个对象,而t1==t4返回 ...

  5. 常量池之字符串常量池String.intern()

    运行时常量池是方法区(PermGen)的一部分. 需要提前了解: 1. JVM内存模型. 2. JAVA对象在JVM中内存分配 常量池的好处 常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现 ...

  6. java string 常量池_用了这么久Java String,你真的懂字符串常量池吗?

    字符串问题可谓是 Java 中经久不衰的问题,尤其是字符串常量池经常作为面试题出现.可即便是看似简单而又经常被提起的问题,还是有好多同学一知半解,看上去懂了,仔细分析起来却又发现不太明白. 本文以 J ...

  7. String:字符串常量池

    一.设计思想   为字符串开辟一个字符串常量池,创建字符串常量时,首先检测字符串常量池是否存在该字符串.如存在该字符串对象,返回其引用:若不存在,实例化该字符串并放入常量池中,并返回其引用. 二.实现 ...

  8. JDK1.8+的String(字符串)常量池理解

    在工作中使用String的地方很多,但是有时候会产生一点疑问,那就是项目中用到了这么多String,会不会对内存造成一定的压力,会不会降低程序的性能,字符串的值都存放到哪里去了?所以就深入了解了一下. ...

  9. JVM---StringTable(字符串常量池)

    StringTable(字符串常量池) 字符串常量池 StringTable(字符串常量池) String的基本特性 String 的底层结构 String 的内存分配 String 的基本操作 字符 ...

最新文章

  1. XenStore: 使用,结构和原理
  2. tensorflow随笔-检测浮点数类型check_numerics
  3. 上海博彦科技 千万别来_这个年产值2870亿元的科技园区,将率多家企业亮相本届服贸会...
  4. get_children 方法里面参数 iv_as_copy 有什么用?
  5. [再学Python] - 6 - 函数的定义调用与返回
  6. 从零基础入门Tensorflow2.0 ----七、34 embedding rnn
  7. 从一个小Demo看React的diff算法
  8. Windows10 地平线4支持PS4手柄有线连接
  9. ACCESS中Dlookup函数使用
  10. matlab小苹果,我要用计算器弹曲子,求亲们发点计算器简谱
  11. BZOJ3168. 【HEOI2013】钙铁锌硒维生素
  12. 顺丰控股亏损:或时效件面临见顶危机,或下沉市场厮杀,或为220亿定增设局?
  13. Python零基础速成班-第1讲-认识Python,课程目标,安装环境以及完成第一行代码“hello world”
  14. 二级c语言编译完程序如何运行,计算机二级C语言辅导:C++环境下编译和运行c语言...
  15. html5定义一个变量,JavaScript 变量
  16. FIFO就是 first in first out 先进先出
  17. 良心推荐几款好玩的生存类手游:方舟生存进化、饥荒等等
  18. 政府网站绩效评估指标和要点
  19. 基于SSM的教务管理系统设计与实现
  20. 热点全能服务器系统,云服务器win系统开热点

热门文章

  1. DB2 错误代码 命令大全
  2. swiper链接href无效
  3. 计算机网络概述(一)
  4. android10全局黑暗,传Android 11或加入自动切换全局黑暗模式功能
  5. c#使用Path.Combine的一个坑
  6. php怎么实现简单的mvc框架,php实现简单的MVC框架实例
  7. spring版本 jdk8_从JDK8升级到JDK11,看这篇就足够了
  8. 服务器物品展示框刷物品,我的世界1period;11period;2展示框刷物品bug | 手游网游页游攻略大全...
  9. cmd中加载java源文件_如何在cmd中编译和运行java源文件
  10. RuntimeError: CUDA out of memory. Tried to allocate 132.00 MiB (GPU 2; 3.95 GiB total capacity; 3.41