Java字符串就该这样设计
一翻开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字符串就该这样设计相关推荐
- java字符串逐个分解_改进JAVA字符串分解的方法
改进JAVA字符串分解的方法 一.概述 大多数Java程序员都曾经使用过java.util.StringTokenizer类.它是一个很方便的字符串分解器,主要用来根据分隔符把字符串分割成标记(Tok ...
- Java字符串的10大热点问题盘点
Java字符串的10大热点问题盘点 下面我为大家总结了10条Java开发者经常会提的关于Java字符串的问题,如果你也是Java初学者,仔细看看吧: 1.如何比较字符串,应该用"==&quo ...
- java字符串操作_Java的字符串操作
Java的字符串操作 小型送分题:Java有字符串(String),StringBuffer(字符串缓存),StringBuilder(字符串建造者?)各种实现,究其原因还是历史上的各种坑. 一.不同 ...
- Java语言语法语义分析器设计与实现
http://tol.bit.edu.cn/Able.Acc2.Web/Template/View.aspx?wmz=3126&courseType=1&courseId=1959&a ...
- java 字符串文字筛选_重新开始Java的原始字符串文字讨论
java 字符串文字筛选 在2018年12月宣布 将从JDK 12中删除原始字符串文字 . 现在,在新的一年中,与Java中原始字符串文字的设计有关的讨论又开始了. 在琥珀色专家OpenJDK邮件列表 ...
- 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 ...
- JAVA语言考试系统的设计与实现(论文+源代码+文献综述+外文翻译+开题报告)
毕业论文(设计)开题报告 论文题目: java考试系统 学生姓名: 年级(学号): 二级学院: 专业: 指导教师: 职称: 填表日期:20 年 月 日 学 院 教 务 处 制 一.选题依据(背景与意义 ...
- 基于Java的坦克游戏大战设计与实现(附论文)
大家好,很高兴和大家分享源码.不管是什么样的需求.都希望各位计算机专业的同学们有一个提高.关于源码如何获取的方式, 大家可以通过常用的搜索引擎,以百度为例,搜索 源码乐园 code51 ,然后再次搜索 ...
- [网络安全课设]基于JAVA的系统端口扫描软件设计实现(java代码+IDEA+UI图形界面+实验报告)
链接::l基于JAVA的系统端口扫描软件设计实现(java代码+IDEA+UI图形界面+实验报告) 系统端口扫描软件设计实现 设计目的和任务 参照superscan.nmap等端口扫描软件的运行情况, ...
最新文章
- java离职交接文档_离职了就没责任?会计离职没办这2项交接,要承担法律责任!...
- 在Java中将Double转换为Integer
- java并发排序_Java基于fork/koin类实现并发排序
- stm32超声波扫频_基于STM32的脉冲式及扫频式超声波除垢信号源设计
- linux mysql ibd_MySQL:如何从ibd文件中恢复数据
- 十进制 转换 2-10 进制,int的扩展方法
- mysql中find_in_set()函数的使用及in()用法详解
- 【转】CT解析重建**
- mysql 5.6 5.7不兼容_同一条sql在mysql5.6和5.7版本遇到的问题。
- jRating五星评级
- 预测!显卡容量10年左右会超过500GB。■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■...
- springboot map数据类型注入_Spring Boot(五):春眠不觉晓,Mybatis知多少
- Linux 设备驱动的固件加载【转】
- webRTC之Mesh/MCU/SFU通信架构区别(九)
- 智能平台管理接口 (IPMI)
- java 封装优化工具,Java开源封装工具
- python+opencv简单人脸识别(源码)(有手就行)
- citypicker城市选择+高德定位,城市编码统一设置
- Mugeda(木疙瘩)H5案例课—重力感应类H5-岑远科-专题视频课程
- 基于Nebula3的游戏: 龙歌:黑暗之眼 试玩下载
热门文章
- 围观各大企业如何活用人工智能,并运用实践?
- 容量是GPT-2的1.7倍!谷歌打造神经对话模型Meena
- 2020 年技术趋势一览:AutoML、联邦学习、云寡头时代的终结
- SAP 如何看某个TR是否传入了Q或者P系统?
- 香港电影黄金配角,虽其貌不扬,演技却吊打小鲜肉,你认识几个
- 2019年上半年收集到的人工智能LSTM干货文章
- 干货丨 简述迁移学习在深度学习中的应用
- 重磅:国拨概算5.34亿!“新一代人工智能”重大项目项目申报指南发布
- 美国再出半导体新法案!1800亿谋求芯片制造振兴
- 《数字孪生体技术白皮书(2019)》(简版)全文