一文弄懂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 ...
随机推荐
- RK3568开发笔记(二):入手RK3568开发板的套件介绍、底板介绍和外设测试
前言 本篇主要介绍RK3568芯片和入手开发板的底板介绍以及开发板的外设. 开发板 笔者的开发板是全套+10.1寸屏. 开发板实物 开发板资源 开发版本提供资料 开发 ...
- 【八股cover#2】CPP语法 Q&A与知识点
CPP语法 Q&A与知识点 简历cover 1.熟练使用C的指针应用及内存管理 指针与引用的区别 指针是一个存储地址的变量,可以有多级,可以为空,并且在初始化后可以改变指向: 引用是原变量的别 ...
- mysql常用语句(持续更新)
查询数据库中各表数量 select table_name,table_rows from information_schema.tables where TABLE_SCHEMA = 'miot' o ...
- 【Azure Redis】中国区Redis在东三区的资源无法在通过门户上与北三区资源之间建立灾备链接
问题描述 为应用启用灾备管理,在北三区建立了一个Azure Redis,同时,在东三区也建立了一个同样的Prem级Redis服务.但是在建立灾备(DR:Disease Recovery)时候,却无法选 ...
- 磁盘 U盘找不到
及磁盘找不到了, 第一步: 看排线是否插好,稳当 第二步:在磁盘管理下面,磁盘是否还在,如果磁盘显示在,只是没有磁盘符 第三步:diskpart ,进入磁盘 其他的命令自己 查询 第四步:进入 CM ...
- Docker下搭建MySql主从复制
在Docker环境下搭建MySql主从复制,阅读此文章默认读者具备基础的Docker命令操作. 一.环境 1.Docker版本:Docker version 24.0.5, build ced0996 ...
- 并行化优化KD树算法:使用C#实现高效的最近邻搜索
本文信息 中文名:<并行化优化KD树算法:使用C#实现高效的最近邻搜索> 英文名:"Parallelized Optimization of KD-Tree Algorithm: ...
- ymal & properties 赋值特性 JSR303数据校验
基本语法 1.空格不能省略 2.以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的. 3.属性和值的大小写都是十分敏感的. key:空格value 字面量直接写在后面就可以 , 字符串默认 ...
- 摆脱鼠标系列 - vscode 上一个编辑器 下一个编辑器 Ctrl + h Ctrl + l
摆脱鼠标系列 - vscode 上一个编辑器 下一个编辑器 Ctrl + H Ctrl + L 为什么 根据 hjkl h是左边的原则 h 左移一位 b 左移一个单词 H 移动到句首 0 是行首 I是 ...
- KeyCastOW win10 屏幕显示按键 - 屏幕录像用
KeyCastOW win10 屏幕显示按键 - 屏幕录像用 https://gitee.com/itas109/KeyCastOW/releases/v2.0.2.5-cn