老生常谈Java String字符串(必看篇)
作者:jingxian 发布时间:2023-06-20 19:56:20
Java中字符串对象创建有两种形式,一种为字面量形式,如String str = "hello";,另一种就是使用new这种标准的构造对象的方法,如String str = new String("hello");
对于这样的常识,不再赘述。
首先String类是final类,为什么定义成final形式呢?
简单点说,对于如此高频率被使用的数据类型,设计者们认为已经设计的足够优秀了,不需要被继承,否则胡乱继承重写可能会降低程序的性能。
正如标题所述,既然深入,那我们就挖下String在jvm层面的小动作。
先解释字面量创建的形式:
当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。
如下所示:
String str1 = "hello" ;
当我们第一次创建的时候,这里我们认为没有内容为hello的对象存在。JVM通过字符串常量池查找不到内容为hello的字符串对象存在,那么会创建这个字符串对象,然后将刚创建的对象的引用放入到字符串常量池中,并且将引用返回给变量str1
如果接下来有这样一段代码
String str2 = "hello" ;
同样JVM还是要检测这个字面量,JVM通过查找字符串常量池,发现内容为”hello”字符串对象存在,于是将已经存在的字符串对象的引用返回给变量str2。注意这里不会重新创建新的字符串对象。
验证是否为str1和str2是否指向同一对象,我们可以通过这段代码
System.out.println(str1 == str2);
结果为true。
第二种使用new创建:
String str3 = new String("hello");
当我们使用了new来构造字符串对象的时候,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。因此我们使用下面代码测试一下,
String str3 = new String("hello");
System.out.println(str1 == str3);
结果为false。说明这两个引用指向不同的对象。
intern
对于上面使用new创建的字符串对象,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。
调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。
String str4 = str3.intern();
System.out.println(str4 == str1);
结果为true。
疑难问题
前提条件?
字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。
引用 or 对象
字符串常量池中存放的时引用还是对象,这个问题是最常见的。字符串常量池存放的是对象引用,不是对象。在Java中,对象都创建在堆内存中。字符串常量池存在于堆内存中的永久代
优缺点
字符串常量池的好处就是减少相同内容字符串的创建,节省内存空间。
如果硬要说弊端的话,就是牺牲了CPU计算时间来换空间。CPU计算时间主要用于在字符串常量池中查找是否有内容相同对象的引用。不过其内部实现为HashTable,所以计算成本较低。
GC回收?
因为字符串常量池中持有了共享的字符串对象的引用,这就是说是不是会导致这些对象无法回收?
首先问题中共享的对象一般情况下都比较小。据我查证了解,在早期的版本中确实存在这样的问题,但是随着弱引用的引入,目前这个问题应该没有了。
intern使用?
关于使用intern的前提就是你清楚自己确实需要使用。比如,我们这里有一份上百万的记录,其中记录的某个值多次为美国加利福尼亚州,我们不想创建上百万条这样的字符串对象,我们可以使用intern只在内存中保留一份即可。
总有例外?
你知道下面的代码,会创建几个字符串对象,在字符串常量池中保存几个引用么?
String test = "a" + "b" + "c";
答案是只创建了一个对象,在常量池中也只保存一个引用。我们使用javap反编译看一下即可得知。
实际上在编译期间,已经将这三个字面量合成了一个。这样做实际上是一种优化,避免了创建多余的字符串对象,也没有发生字符串拼接问题。
来源:http://www.cnblogs.com/xinde123/p/7339911.html


猜你喜欢
- 一、findById(ID id)通过id进行单条查询,先看看 findById(ID id) 的源码@Overridepublic Opt
- 引言今天给大家介绍一个非常有意思类库,基于java实现的简繁体转换,适用于后端、android等开发领域源码地址:* liuyueyi/qu
- 常用的Dialog有确认对话框,单选按钮对话框,多选按钮对话框,复选按钮对话框另外还有自定义的对话框AlertDialog的常用方法setT
- 本文以实例形式介绍了基于Java实现的Dijkstra算法,相信对于读者研究学习数据结构域算法有一定的帮助。Dijkstra提出按各顶点与源
- 目录1、下面的代码运行的结果是:2、下面有关java实例变量,局部变量,类变量和final变量的说法,错误的是?3、执行如下代码段后,变量s
- 前言相信很多Java开发都遇到过一个面试题:Resource和Autowired的区别是什么?这个问题的答案相信基本都清楚,但是这两者在Sp
- 方法一(推荐):设置datetimepicker的属性ShowCheckBox为true在窗口初始化时候,添加代码this.datetime
- 今天要分享一个非常简单的功能:使用Android原生控件Gallery实现照片拖动的特效实现思路如下:在布局文件中定义一个Gallery控件
- 在项目中有使用到延时队列的场景,做个简单的记录说明;首先DelayQueue实现了BlockingQueue,加入其中的元素必须实现Dela
- 背景SpringBoot的应用监控方案比较多,SpringBoot+Prometheus+Grafana是目前比较常用的方案之一。它们三者之
- 本文研究的主要是Java编程利用openoffice将doc、docx转为pdf的实现代码,具体如下。1. 需要用的软件OpenOffice
- 一、实现对ScrollViewer样式的自定义主要包括:1、滚动条宽度设置2、滚动条颜色3、滚动条圆角4、滚动条拉动时的效果mouseove
- 一、网站微信扫码支付开发并没有现成的java示例,总结一下自己微信扫码支付心得二、首先去微信公众平台申请账户 https://mp.weix
- 运行在TCP之上常见的网络应用协议有比如HTTP、FTP、SMTP、POP3、IMAP。TCP是TCP/IP体系中最重要的传输协议,它提供全
- Java的动态绑定所谓的动态绑定就是指程执行期间(而不是在编译期间)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。java继承
- 本文实例为大家分享了java实现图书馆管理系统的具体代码,供大家参考,具体内容如下思路:所有包都在book_manage包里利用面向对象的多
- 前言使用过SpringBoot的都应该知道,一个SpringBoot 项目就是由一个一个 Starter 组成的,一个 Starter 代表
- java spring 通过注解方式创建对象首先 我们要搞清楚一个基础概念什么是注解?注解可以说是代码里的一些特殊标记。格式是 @() 里面
- 前言在开发 Flutter 应用程序时,我们需要有一个组件来管理全局设置,包括主题、导航和路由。这就是 MaterialApp 的用途。作为
- RestTemplate加@Autowired注入不了1、在启动类加入如图箭头所示代码:然后在进行@Autowired发现不报错了。完美解决