一翻开Java面试题,基本上都会有考察字符串的不可变性,new String()和“”的区别,字符串+内部实现等相关问题,您可能也知道常量池,看了一些堆栈图,了解了上述答案,可是过阵子可能就会模糊,因为也许不懂它为什么要这样设计。

本文将从为什么这么设计,到你也是这样设计的认知过程,带你去了解一下Java字符串,有了这个过程,你就很难忘记,因为它本身就该如此。

所谓常量池

String s1 =  "abc";
String s2 =  "abc";
String s3 =  "abc";
String s4 =  "abc";
复制代码

上述代码我们不考虑什么“abc”几份,先考虑一下如果你有这样的代码,你该怎么优化,很显然,这里的“abc”都是一样的,而我居然傻啦吧唧的写了4份,继续下去还不得累死,所以优化如下:

// 建立字符串常量
String constant  = "abc";
String s1 =  constant;
String s2 =  constant;
String s3 =  constant;
String s4 =  constant;
复制代码

上述优化是很自然的,那么javac编译时也不傻,即使我们没有做上述优化,javac编译时也会建立一个UTF-8常量,形式如下:

Constant pool:
……
#31 = Utf8               abc
……
复制代码

而后s1,s2,s3,s4最终值都会引用到这个#31,你会发现,这和你自己优化所建立的字符串常量是一个意思,没有任何特殊之处,对的,这就是很自然的设计,所以每个.java文件编译成.class文件的时候,都会有一个块重要的数据,叫做Constant pool(常量池),就是用来存储这些所谓的常量,比如上述的“abc”,当然你的类名,方法名,字段名,变量名最终都会存储为UTF-8常量,还有其它,这里就不复述了,通过javap -v xxx.class可以很直观的看到所有常量池的数据。

回到面试题,s1,s2,s3,s4是一个值么?答案是废话啊,不然我要写4份么,既然是一份,那么地址和值怎么可能不同呢?

在实际应用中,我们通常会建立一个常量类,用来表示常量,例如:

public class Constant {public static final String STR_CONST = "abc";
}
复制代码

其它任何类的方法使用都调用Constant.STR_CONST即可,我们都知道这样“abc”只有一份,而且不可变,那么很显然, Jvm也不傻,当它把所有.class中的Constant pool(常量池)数据放入Jvm内存中一个专门区域(运行时常量池),发现有多份"abc"的时候,Jvm和我们一样只保存一份,就如同上述STR_CONST一样,其它引用这一份即可。

所以“abc”这个常量本身,在Jvm中只会有一份,换做我们,上述常量类中STR_CONST不也是这个意思么,太自然了。

所谓字符串不可变性

当我们建立了常量:

public static final String STR_CONST = "abc";
复制代码

为什么要加final?因为我们知道很多地方引用了这个STR_CONST,如果不加final,STR_CONST一旦改变,所有引用这个值得都改变了,增加了不可确定性,程序会不可控。

通过上节你知道,Jvm会把“abc”作为常量,只存储到运行时常量池一份,就如同我们建立的STR_CONST一样,那么我们都知道要设置final让其不可变,Jvm当然也知道,Jvm中的"abc"被很多地方引用,当然也要不可变,这样系统才健硕,这也是很自然的一个过程,所以类似下面的操作。

String constant  = "abc";
constant.toUpperCase()
constant.substring(2);
constant = constant + "ef";
……
复制代码

都是不会改变"abc"本身的,就如同我们会用STR_CONST来进行其他操作,但是却不会改变STR_CONST本身值一样,Jvm同样不傻,也不会改变"abc"本身的,这是一个道理。

其实上述操作本质都是创建了一个新的String对象,new String(...),而不是对“abc”的操作,那么new有什么不一样呢?

String constant  = "abc";
String str = new String("abc")
复制代码

new String("abc")和常量池完全没关系了么?,并不是,new String("abc")里的"abc",其实还是引用常量池的"abc"。

但是因为是new, 创建了一个新对象,和所有创建对象一样都经过了new(创建对象,分配堆空间,为堆空间初始化零值),invokespecial(调用构造方法,写入实例变量值)等指令,最终在堆有才有了一份String对象,而且str引用它。

我们的"abc"是存储在运行时常量池的,被很多地方引用,而str是一个对象,存储在堆中,它们属于不同的内存空间,所以单纯比较地址(==)是肯定不同的。

所谓+内部实现

String constant = "abc";
String result = constant + "ef";
复制代码

我们现在都知道 + 内部其实是调用StringBuilder来实现的,StringBuilder内部有一个可扩容的char[] value,初始是16,上述+"ef",不需要扩容,16完全能满足。

看起来大材小用,然而如果让你提供一个+操作,当然不能只考虑上述这么简单的情况,多次+操作呢,循环+操作呢,StringBuilder作为一个通用的实现,就是为了一次解决上述各种问题的,我们实际开发中尽可能的让一个方法能兼容一种操作的多种情况,那么Javac编译也是相同的,一遇到+号,就直接编译成StringBuilder来操作,这样我们实际开发中的各种+操作,最终都将是高效的,换做我们不也会这样设计么。

最后

我们开发学习中会遇到很多所谓的术语,它们提炼的很好,然而通常都没有配以很好的解释,最终只记得术语,其实,拨开术语的面纱,大多数术语内部思想是很简单易懂的,毕竟也是人通过经验总结的,当理解了内部思想后,术语什么的只是一段文字了而已了。

转载于:https://juejin.im/post/5c9322745188252d65344915

Java字符串就该这样设计相关推荐

  1. java字符串逐个分解_改进JAVA字符串分解的方法

    改进JAVA字符串分解的方法 一.概述 大多数Java程序员都曾经使用过java.util.StringTokenizer类.它是一个很方便的字符串分解器,主要用来根据分隔符把字符串分割成标记(Tok ...

  2. Java字符串的10大热点问题盘点

    Java字符串的10大热点问题盘点 下面我为大家总结了10条Java开发者经常会提的关于Java字符串的问题,如果你也是Java初学者,仔细看看吧: 1.如何比较字符串,应该用"==&quo ...

  3. java字符串操作_Java的字符串操作

    Java的字符串操作 小型送分题:Java有字符串(String),StringBuffer(字符串缓存),StringBuilder(字符串建造者?)各种实现,究其原因还是历史上的各种坑. 一.不同 ...

  4. Java语言语法语义分析器设计与实现

    http://tol.bit.edu.cn/Able.Acc2.Web/Template/View.aspx?wmz=3126&courseType=1&courseId=1959&a ...

  5. java 字符串文字筛选_重新开始Java的原始字符串文字讨论

    java 字符串文字筛选 在2018年12月宣布 将从JDK 12中删除原始字符串文字 . 现在,在新的一年中,与Java中原始字符串文字的设计有关的讨论又开始了. 在琥珀色专家OpenJDK邮件列表 ...

  6. I/O流(包括操作系统与内核,用户空间),I/O工作原理,Java I/O流的设计及Java IO系统

    文章目录 一.操作系统与内核 1.1操作系统 1.2内核 1.3 关系图 二.内核空间和用户空间 2.1:目的: 2.2.内核空间(Kernel-space): 2.3.用户空间(User-space ...

  7. JAVA语言考试系统的设计与实现(论文+源代码+文献综述+外文翻译+开题报告)

    毕业论文(设计)开题报告 论文题目: java考试系统 学生姓名: 年级(学号): 二级学院: 专业: 指导教师: 职称: 填表日期:20 年 月 日 学 院 教 务 处 制 一.选题依据(背景与意义 ...

  8. 基于Java的坦克游戏大战设计与实现(附论文)

    大家好,很高兴和大家分享源码.不管是什么样的需求.都希望各位计算机专业的同学们有一个提高.关于源码如何获取的方式, 大家可以通过常用的搜索引擎,以百度为例,搜索 源码乐园 code51 ,然后再次搜索 ...

  9. [网络安全课设]基于JAVA的系统端口扫描软件设计实现(java代码+IDEA+UI图形界面+实验报告)

    链接::l基于JAVA的系统端口扫描软件设计实现(java代码+IDEA+UI图形界面+实验报告) 系统端口扫描软件设计实现 设计目的和任务 参照superscan.nmap等端口扫描软件的运行情况, ...

最新文章

  1. java离职交接文档_离职了就没责任?会计离职没办这2项交接,要承担法律责任!...
  2. 在Java中将Double转换为Integer
  3. java并发排序_Java基于fork/koin类实现并发排序
  4. stm32超声波扫频_基于STM32的脉冲式及扫频式超声波除垢信号源设计
  5. linux mysql ibd_MySQL:如何从ibd文件中恢复数据
  6. 十进制 转换 2-10 进制,int的扩展方法
  7. mysql中find_in_set()函数的使用及in()用法详解
  8. 【转】CT解析重建**
  9. mysql 5.6 5.7不兼容_同一条sql在mysql5.6和5.7版本遇到的问题。
  10. jRating五星评级
  11. 预测!显卡容量10年左右会超过500GB。■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■...
  12. springboot map数据类型注入_Spring Boot(五):春眠不觉晓,Mybatis知多少
  13. Linux 设备驱动的固件加载【转】
  14. webRTC之Mesh/MCU/SFU通信架构区别(九)
  15. 智能平台管理接口 (IPMI)
  16. java 封装优化工具,Java开源封装工具
  17. python+opencv简单人脸识别(源码)(有手就行)
  18. citypicker城市选择+高德定位,城市编码统一设置
  19. Mugeda(木疙瘩)H5案例课—重力感应类H5-岑远科-专题视频课程
  20. 基于Nebula3的游戏: 龙歌:黑暗之眼 试玩下载

热门文章

  1. 围观各大企业如何活用人工智能,并运用实践?
  2. 容量是GPT-2的1.7倍!谷歌打造神经对话模型Meena
  3. 2020 年技术趋势一览:AutoML、联邦学习、云寡头时代的终结
  4. SAP 如何看某个TR是否传入了Q或者P系统?
  5. 香港电影黄金配角,虽其貌不扬,演技却吊打小鲜肉,你认识几个
  6. 2019年上半年收集到的人工智能LSTM干货文章
  7. 干货丨 简述迁移学习在深度学习中的应用
  8. 重磅:国拨概算5.34亿!“新一代人工智能”重大项目项目申报指南发布
  9. 美国再出半导体新法案!1800亿谋求芯片制造振兴
  10. 《数字孪生体技术白皮书(2019)》(简版)全文