一文弄懂String的所有小秘密
文章目录
- 简介
- String是不可变的
- 传值还是传引用
- substring() 导致的内存泄露
- 总结
一文弄懂String的所有小秘密
简介
String是java中非常常用的一个对象类型。可以说java中使用最多的就是String了。那么String到底有哪些秘密呢?接下来本文将会一一讲解。
String是不可变的
String是不可变的,官方的说法叫做immutable或者constant。
String的底层其实是一个Char的数组。
private final char value[];
所有的String字面量比如"abc"都是String的实现。
考虑下面的赋值操作:
String a="abc";
String b="abc";
对于java虚拟机来说,"abc"是字符串字面量,在JDK 7之后,这个字符串字面量是存储在java heap中的。而在JDK 7之前是有个专门的方法区来存储的。
有了“abc”,然后我们将“abc” 赋值给a和b。
可以看到这里a和b只是java heap中字符串的引用。
再看看下面的代码发生了什么:
String c= new String("abc");
首先在java heap中创建了“abc”,然后调用String的构造函数:
public String(String original) {this.value = original.value;this.hash = original.hash;}
在构造函数中,String将底层的字符串数组赋值给value。
因为Array的赋值只是引用的赋值,所以上述new操作并不会产生新的字符串字面值。
但是new操作新创建了一个String对象,并将其赋值给了c。
String的不可变性还在于,String的所有操作都会产生新的字符串字面量。原来的字符串是永远不会变化的。
字符串不变的好处就在于,它是线程安全的。任何线程都可以很安全的读取字符串。
传值还是传引用
一直以来,java开发者都有这样的问题,java到底是传值还是传引用呢?
我想,这个问题可以从两方面来考虑。
首先对于基础类型int,long,double来说,对他们的赋值是值的拷贝。而对于对象来说,赋值操作是引用。
另一方面,在方法调用的参数中,全部都是传值操作。
public static void main(String[] args) {String x = new String("ab");change(x);System.out.println(x);
}public static void change(String x) {x = "cd";
}
我们看上面的例子,上面的例子输出ab。因为x是对“ab”的引用,但是在change方法中,因为是传值调用,所以会创建一个新的x,其值是“ab”的引用地址。当x被重新赋值之后,改变的只是拷贝之后的x值。而本身的x值是不变的。
substring() 导致的内存泄露
第一次看到这个话题,大家可能会很惊讶,substring方法居然会导致内存泄露?这个话题要从JDK 6开始讲起。
我们先看下JDK 6的实现:
String(int offset, int count, char value[]) {this.value = value;this.offset = offset;this.count = count;
}public String substring(int beginIndex, int endIndex) {//check boundaryreturn new String(offset + beginIndex, endIndex - beginIndex, value);
}
可以看到,JDK 6的substring方法底层还是引用的原始的字符串数组。唯一的区别就是offset和count不同。
我们考虑一下下面的应用:
String string = "abcdef";
String subString = string.substring(1, 3);
string = null;
虽然最后我们将String赋值为null,但是subString仍然引用了最初的string。将不会被垃圾回收。
在JDK 7之后,String的实现发送了变化:
public String(char value[], int offset, int count) {//check boundarythis.value = Arrays.copyOfRange(value, offset, offset + count);
}public String substring(int beginIndex, int endIndex) {//check boundaryint subLen = endIndex - beginIndex;return new String(value, beginIndex, subLen);
}
Arrays.copyOfRange将会拷贝一份新的数组,而不是使用之前的数组。从而不会发生上面的内存泄露的问题。
总结
虽然String是我们经常使用的对象,但是里面的原理还是值得我们了解的。
更多精彩内容且看:
- 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
- Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
- Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
- java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/string-all-in-one/
本文来源:flydean的博客
欢迎关注我的公众号:程序那些事,更多精彩等着您!
一文弄懂String的所有小秘密相关推荐
- 一文弄懂EnumMap和EnumSet
文章目录 简介 EnumMap 什么时候使用EnumMap EnumSet 总结 一文弄懂EnumMap和EnumSet 简介 一般来说我们会选择使用HashMap来存储key-value格式的数据, ...
- deque stack java_一文弄懂java中的Queue家族
简介 java中Collection集合有三大家族List,Set和Queue.当然Map也算是一种集合类,但Map并不继承Collection接口. List,Set在我们的工作中会经常使用,通常用 ...
- 一文弄懂元学习 (Meta Learing)(附代码实战)《繁凡的深度学习笔记》第 15 章 元学习详解 (上)万字中文综述
<繁凡的深度学习笔记>第 15 章 元学习详解 (上)万字中文综述(DL笔记整理系列) 3043331995@qq.com https://fanfansann.blog.csdn.net ...
- 一文弄懂神经网络中的反向传播法
最近在看深度学习的东西,一开始看的吴恩达的UFLDL教程,有中文版就直接看了,后来发现有些地方总是不是很明确,又去看英文版,然后又找了些资料看,才发现,中文版的译者在翻译的时候会对省略的公式推导过程进 ...
- 一文弄懂各种loss function
有模型就要定义损失函数(又叫目标函数),没有损失函数,模型就失去了优化的方向.大家往往接触的损失函数比较少,比如回归就是MSE,MAE,分类就是log loss,交叉熵.在各个模型中,目标函数往往都是 ...
- 一文弄懂神经网络中的反向传播法——BackPropagation【转】
本文转载自:https://www.cnblogs.com/charlotte77/p/5629865.html 一文弄懂神经网络中的反向传播法--BackPropagation 最近在看深度学习的东 ...
- CAD2010 为了保护_一文弄懂,锂电池的充电电路,以及它的保护电路方案设计
原标题:一文弄懂,锂电池的充电电路,以及它的保护电路方案设计 锂电池特性 首先,芯片哥问一句简单的问题,为什么很多电池都是锂电池? 锂电池,工程师对它都不会感到陌生.在电子产品项目开发的过程中,尤其是 ...
- 一文弄懂Flink网络流控及反压
一文弄懂Flink网络流控及反压 1. 为什么需要网络流控? 2. 网络流控的实现:静态限速 3. 网络流控的实现:动态反馈/自动反压 3.1 案例一:Storm 反压实现 3.2 案例二:Spark ...
- 一文弄懂halcon例程:rim.hdev
一文弄懂halcon例程:rim.hdev 打怪的路上总是无聊的,但是也不能不打啊,我自己现在也在每天打怪升级呢.昨天就因为一个问题,我到视觉群问里面的大牛,结果,他不帮我解答,他不告诉我怎么解决就算 ...
最新文章
- java中JFrame类中函数addWindowListener(new WindowAdapter)
- .NET框架设计—常被忽视的框架设计技巧
- 美国农业生产与农产品国际贸易 对话国际农民丰收节贸易会
- 【Linux网络编程】原始套接字实例:MAC 地址扫描器
- HttpClient的简单使用
- 八个老师随机分配三个办公室
- python合并csv文件_Python学习——pandas 合并csv文件
- tensorFlow13卷积神经网络发展
- 贪婪算法在求解最小生成树中的应用(JAVA)--Prim算法
- “熊猫血”产妇诞双胞胎困难 丈夫全城寻找血源
- Windbg 查看SSDT表
- docker 笔记(2) -- 镜像
- 设置element-iu中table滚动条位置
- 三星宣布7nm LPP芯片量产!性能高20%,功耗降50%,面积降40%
- Mongoose源码分析之--简单的服务器搭建(C语言)
- vim编辑器操作汇总
- React 路由 中 BrowserHistory 刷新报404
- 利用HTML简单语句来制作个人简历
- 商淘软件五周年:着力打造S2B2C及电商一站式服务专家
- Notepad++添加读取十六进制插件HexEditor
热门文章
- ubuntu安装linux deepin,如何在Ubuntu中安装Deepin终端 | MOS86
- SlopOne推荐算法
- Burnside引理和Polya定理学习笔记
- PostgreSQL学习笔记1之表定义
- cocos2d-x初探学习笔记(12)--图形绘制
- C++ STL : 模拟实现STL中的关联式容器unordered_map/unordered_set
- scrapy设置代理的方法
- 微服务架构统一安全认证设计与实践
- 干货!全面认识Docker和基本指令
- 以高并发著称的 Go 如何与 MySQL 搭档应对千亿级数据?