一文弄懂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 boundary
return 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 boundary
this.value = Arrays.copyOfRange(value, offset, offset + count);
}
public String substring(int beginIndex, int endIndex) {
//check boundary
int subLen = endIndex - beginIndex;
return new String(value, beginIndex, subLen);
}
Arrays.copyOfRange将会拷贝一份新的数组,而不是使用之前的数组。从而不会发生上面的内存泄露的问题。
总结
虽然String是我们经常使用的对象,但是里面的原理还是值得我们了解的。
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/string-all-in-one/
本文来源:flydean的博客
欢迎关注我的公众号:程序那些事,更多精彩等着您!
一文弄懂String的所有小秘密的更多相关文章
- 一文弄懂-Netty核心功能及线程模型
目录 一. Netty是什么? 二. Netty 的使用场景 三. Netty通讯示例 1. Netty的maven依赖 2. 服务端代码 3. 客户端代码 四. Netty线程模型 五. Netty ...
- 一文弄懂-BIO,NIO,AIO
目录 一文弄懂-BIO,NIO,AIO 1. BIO: 同步阻塞IO模型 2. NIO: 同步非阻塞IO模型(多路复用) 3.Epoll函数详解 4.Redis线程模型 5. AIO: 异步非阻塞IO ...
- 一文弄懂神经网络中的反向传播法——BackPropagation【转】
本文转载自:https://www.cnblogs.com/charlotte77/p/5629865.html 一文弄懂神经网络中的反向传播法——BackPropagation 最近在看深度学习 ...
- 一文弄懂-《Scalable IO In Java》
目录 一. <Scalable IO In Java> 是什么? 二. IO架构的演变历程 1. Classic Service Designs 经典服务模型 2. Event-drive ...
- 一文弄懂CGAffineTransform和CTM
一文弄懂CGAffineTransform和CTM 一些概念 坐标空间(系):视图(View)坐标空间与绘制(draw)坐标空间 CTM:全称current transformation matrix ...
- 【TensorFlow】一文弄懂CNN中的padding参数
在深度学习的图像识别领域中,我们经常使用卷积神经网络CNN来对图像进行特征提取,当我们使用TensorFlow搭建自己的CNN时,一般会使用TensorFlow中的卷积函数和池化函数来对图像进行卷积和 ...
- 从字符串到常量池,一文看懂String类设计
从一道面试题开始 看到这个标题,你肯定以为我又要讲这道面试题了 // 这行代码创建了几个对象? String s3 = new String("1"); 是的,没错,我确实要从这里 ...
- 夯实Java基础系列3:一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!
目录 目录 string基础 Java String 类 创建字符串 StringDemo.java 文件代码: String基本用法 创建String对象的常用方法 String中常用的方法,用法如 ...
- 一文弄懂Pytorch的DataLoader, DataSet, Sampler之间的关系
以下内容都是针对Pytorch 1.0-1.1介绍. 很多文章都是从Dataset等对象自下往上进行介绍,但是对于初学者而言,其实这并不好理解,因为有的时候会不自觉地陷入到一些细枝末节中去,而不能把握 ...
- 【Java基本功】一文读懂String及其包装类的实现原理
String作为Java中最常用的引用类型,相对来说基本上都比较熟悉,无论在平时的编码过程中还是在笔试面试中,String都很受到青睐,然而,在使用String过程中,又有较多需要注意的细节之处. S ...
随机推荐
- WSL2镜像文件压缩
WSL2的镜像文件(*.vhdx)支持自动扩容,但是一般不会自动缩容.一旦某次存放过大文件以后,即使后续删除,镜像文件体积仍然不会缩小,导致大量磁盘空间浪费.因此,可以定期对镜像文件进行手动压缩. 镜 ...
- 私有git服务器搭建-gitlib版
目录 环境 centos6.5 这里有官网安装地址教程: 这里有机器配置安装需求 CPU Memory 安装步骤 安装配置依赖项 添加GitLab仓库,并安装到服务器上 启动GitLab 配置 git ...
- 【Azure 应用服务】如何来检查App Service上证书的完整性以及在实例中如何查找证书是否存在呢?
问题描述 1:如何来检查App Service上证书的完整性呢? 2:如何来检查App Service的实例上是否包含这个证书呢? Windows 环境 or Linux 环境? 问题解答 问题一: ...
- 【Azure API 管理】如何修改Azure APIM的管理员邮箱和组织名称
问题描述 当创建一个新的APIM服务时,会要求输入组织名称(Organization name)和管理员邮箱(Administrator email :Set the e-mail address t ...
- 【Azure 应用服务】如何从App Service for Linux 的环境中下载Container中非Home目录下的文件呢?
问题描述 在App Service for Linux的环境中,我们能通过SSH进入到Container的环境中,并且可以通过在kudu站点的URL后面添加 /newui 打开一个适用于Linux环境 ...
- 【Azure Fabric Service】怎样关闭 Azure Service Fabric?
问题描述 怎样关闭Azure Service Fabric服务呢?在Azure门户上没有找到 Stop 按钮. 问题回答 Azure Service Fabric 默认是无法停止的,可以删除. 虽然可 ...
- Hugging Face 表情包来啦!
小编有一个朋友,微信聊基本不回复文字,内容和情绪都化身成表情包直接回复,并且一气呵成.自带上下文衔接.你身边有这样的朋友吗? 作为梦想成为第一家以表情符号上市的公司,以及在社交平台发文 emoji 不 ...
- RocketMQ(7) 消费幂等
1 什么是消费幂等 当出现消费者对某条消息重复消费的情况时,重复消费的结果与消费一次的结果是相同的,并且多次消 费并未对业务系统产生任何负面影响,那么这个消费过程就是消费幂等的. 幂等:若某操作执行多 ...
- 5. JVM虚拟机栈
1.概述 说到jvm 其中让人印象最深的就是栈和堆,也是 jvm中占用内存最大的两个地方. 从宏观上来看栈是运行时的单位,而堆是存储的单位 ,栈解决程序的运行问题,即程序如何执行,或者说如何处理数据. ...
- linux centos文本编辑模式快速进入末尾最后一行快捷键与跳转首行、行尾和某一行快捷键
前言 使用vim的过程中想要快速移动光标至行首.行尾.第一行.最后一行或者某一行,本文对此简单介绍. 具体操作 1.快速至当前行的行首:home键最简单 (1) Home键: (2) 符号^(要按sh ...