什么是字符串常量池?

面试官:请问什么是字符串常量池?

Java设计者为String提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们需要带着以下三个问题,去理解字符串常量池:

  1. 字符串常量池的设计意图是什么?
  2. 字符串常量池在哪里?
  3. 如何操作字符串常量池?

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

字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价。
JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化:

  1. 为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池;
  2. 如果字符串已经存在池中,就返回池中的实例引用;
  3. 如果字符串不在池中,就会实例化一个字符串并放到池中。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突进行共享;

实现的基础:

  1. 因为字符串是不可变的,可以不用担心数据冲突进行共享;
  2. 运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收

我们来看下面一段代码,就是从字符串常量池中获取相应的字符串:

 String str1 = “hello”;
 String str2 = “hello”;
 System.out.printl("str1与str2比较地址" : str1 == str2 ) //true 
 System.out.printl("str1与str2比较内容" : str1.equals(str2) ) //true 
 /**说明:str1指向的“hello” 与 str2指向的“hello” 共用一块内存空间*/

字符串常量池在哪里?

在分析字符串常量池的位置时,首先得了解JVM内存模型,JVM内存区域分为线程共享区线程独占区
线程共享区包括 [堆] 和 [方法区]
线程独占区包括 [Java虚拟机栈]、[本地方法栈] 和 [陈程序计数器]
Alt
方法区:

  • 存放加载的类信息常量池静态变量静态代码块等信息;
  • 类信息包括类的版本、字段、方法、接口等,方法区也被称为永久代。

程序计数器:

  • 是一块比较小的内存区域,是唯一一个不会发生OutOfMemoryError的区域,可以这样理解方法进栈后,每一行代码都有一个标识,程序按着标识往下执行。

Java虚拟机栈:

  • 每个方法执行,都会创建一个栈帧,方法调用进栈,方法结束出栈; 栈帧里面存放着局部变量表操作数栈动态链接以及方法出口等;
  • 局部变量表里面存放着基本数据类型引用类型等; 栈帧伴随着方法的开始而开始,结束而结束;
  • 局部变量表所需的内存空间在编译期间就完成了分配,在运行期间是不会改变的
  • 栈很容易出现StackOverFlowError,栈内存溢出错误,常见于递归调用

本地方法栈和Java虚拟机栈:

  • 其实是差不多的,但是也是有区别的Java虚拟机栈为Java方法服务本地方法栈为native方法服务

堆:

  • 功能单一,就是存储对象的实例,堆其实又分新生代和老年代;
  • 新生代又分Eden、Survivor01和Survivor02三个区域,垃圾收集器主要管理的区域,Eden区回收效率很高。
  • 并不是所有的对象实例都会分配到堆上去,Java虚拟机栈也会分配。堆很容易出现OutOfMemoryError错误,内存溢出

如何操作字符串常量池?

JVM实例化字符串常量池时

 String s1 = "Hello World";
 String s2 = "Hello World";
 String s3 = new String("Hello World");
 String s4 = s2.intern();
 System.out.println("s1 == s2? " + (s1 == s2)); // true
 System.out.println("s1 == s3? " + (s1 == s3)); // false
 System.out.println("s1 == s4? " + (s1 == s4)); // true

String.intern()判断这个常量是否存在于常量池。
如果存在{
  判断存在内容是引用还是常量{
     如果是引用{
      返回引用地址指向堆空间对象
     } 
     如果是常量{
      直接返回常量池常量
     }
  }
 }
 如果不存在{
   将当前对象引用复制到常量池,并且返回的是当前对象的引用
 }
通过new操作符创建的字符串对象不指向字符串池中的任何对象,但是可以通过使用字符串的intern()方法来指向其中的某一个。java.lang.String.intern()返回一个保留池字符串,就是一个在全局字符串池中有了一个入口。如果以前没有在全局字符串池中,那么它就会被添加到里面。

……
帮助他人,快乐自己,最后,感谢您的阅读!
所以如有纰漏或者建议,还请读者朋友们在评论区不吝指出!
……
个人网站…知识是一种宝贵的资源和财富,益发掘,更益分享…

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值