浅谈Java中字符串的初始化及字符串操作类(上)

简介: 大家好,我是本周的值班编辑 江南一点雨 ,本周将由我为大家排版并送出技术干货,大家可以在公众号后台回复“springboot”,获取最新版 Spring Boot2.1.6 视频教程试看。在深入学习字符串类之前, 我们先搞懂JVM是怎样处理新生字符串的.当你知道字符串的初始化细节后, 再去写 Strings="hello"或 Strings=newString("hello")等代码时, 就能做到心中有数。

在深入学习字符串类之前, 我们先搞懂JVM是怎样处理新生字符串的. 当你知道字符串的初始化细节后, 再去写 Strings="hello"Strings=newString("hello")等代码时, 就能做到心中有数。

首先得搞懂字符串常量池的概念。

常量池是Java的一项技术, 八种基础数据类型除了float和double都实现了常量池技术. 这项技术从字面上是很好理解的: 把经常用到的数据存放在某块内存中, 避免频繁的数据创建与销毁, 实现数据共享, 提高系统性能。

字符串常量池是Java常量池技术的一种实现, 在近代的JDK版本中(1.7后), 字符串常量池被实现在Java堆内存中。

下面通过三行代码让大家对字符串常量池建立初步认识:

public static void main(String[] args) {
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1 == s2); //false
}

我们先来看看第一行代码 Strings1="hello";干了什么.

41.jpg

对于这种直接通过双引号""声明字符串的方式, 虚拟机首先会到字符串常量池中查找该字符串是否已经存在. 如果存在会直接返回该引用, 如果不存在则会在堆内存中创建该字符串对象, 然后到字符串常量池中注册该字符串。

在本案例中虚拟机首先会到字符串常量池中查找是否有存在"hello"字符串对应的引用. 发现没有后会在堆内存创建"hello"字符串对象(内存地址0x0001), 然后到字符串常量池中注册地址为0x0001的"hello"对象, 也就是添加指向0x0001的引用. 最后把字符串对象返回给s1。

温馨提示: 图中的字符串常量池中的数据是虚构的, 由于字符串常量池底层是用HashTable实现的, 存储的是键值对, 为了方便大家理解, 示意图简化了字符串常量池对照表, 并采用了一些虚拟的数值。

 下面看 Strings2=newString("hello");的示意图:

42.jpg

当我们使用new关键字创建字符串对象的时候, JVM将不会查询字符串常量池, 它将会直接在堆内存中创建一个字符串对象, 并返回给所属变量。

所以s1和s2指向的是两个完全不同的对象, 判断s1 == s2的时候会返回false。

 

如果上面的知识理解起来没有问题的话, 下面看些难点的.

{
String s1 = new String("hello ") + new String("world");
s1.intern();
String s2 = "hello world";
System.out.println(s1 == s2); //true
}

第一行代码 Strings1=newString("hello ")+newString("world");的执行过程是这样子的:

1.依次在堆内存中创建"hello "和"world"两个字符串对象

2.然后把它们拼接起来 (底层使用StringBuilder实现, 后面会带大家读反编译代码)

3.在拼接完成后会产生新的"hello world"对象, 这时变量s1指向新对象"hello world"

执行完第一行代码后, 内存是这样子的:

43.jpg

第二行代码 s1.intern();

String类的源码中有对 intern()方法的详细介绍, 翻译过来的意思是: 当调用 intern()方法时, 首先会去常量池中查找是否有该字符串对应的引用, 如果有就直接返回该字符串; 如果没有, 就会在常量池中注册该字符串的引用, 然后返回该字符串。

由于第一行代码采用的是new的方式创建字符串, 所以在字符串常量池中没有保存"hello world"对应的引用, 虚拟机会在常量池中进行注册, 注册完后的内存示意图如下:

44.jpg

第三行代码 Strings2="hello world";

这种直接通过双引号""声明字符串背后的运行机制我们在第一个案例提到过, 这里正好复习一下。

首先虚拟机会去检查字符串常量池, 发现有指向"hello world"的引用. 然后把该引用所指向的字符串直接返回给所属变量。

执行完第三行代码后, 内存示意图如下:

45.jpg

如图所示, s1和s2指向的是相同的对象, 所以当判断s1 == s2时返回true。

最后我们对字符串常量池进行总结:

当用new关键字创建字符串对象时, 不会查询字符串常量池; 当用双引号直接声明字符串对象时, 虚拟机将会查询字符串常量池. 说白了就是: 字符串常量池提供了字符串的复用功能, 除非我们要显式创建新的字符串对象, 否则对同一个字符串虚拟机只会维护一份拷贝。

相关文章
|
9天前
|
Java
Java 字符串分割split空字符串丢失解决方案
Java 字符串分割split空字符串丢失解决方案
|
1天前
|
Java 编译器
Java Character 类
4月更文挑战第13天
|
2天前
|
存储 Java
Java基础教程(7)-Java中的面向对象和类
【4月更文挑战第7天】Java是面向对象编程(OOP)语言,强调将事务抽象成对象。面向对象与面向过程的区别在于,前者通过对象间的交互解决问题,后者按步骤顺序执行。类是对象的模板,对象是类的实例。创建类使用`class`关键字,对象通过`new`运算符动态分配内存。方法包括构造函数和一般方法,构造函数用于对象初始化,一般方法处理逻辑。方法可以有0个或多个参数,可变参数用`类型...`定义。`this`关键字用于访问当前对象的属性。
|
5天前
|
Java Shell
Java 21颠覆传统:未命名类与实例Main方法的编码变革
Java 21颠覆传统:未命名类与实例Main方法的编码变革
10 0
|
5天前
|
Java
Java 15 神秘登场:隐藏类解析未知领域
Java 15 神秘登场:隐藏类解析未知领域
10 0
|
7天前
|
安全 Java
append在Java中是哪个类下的方法
append在Java中是哪个类下的方法
21 9
|
8天前
|
JavaScript Java 测试技术
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
25 0
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
|
8天前
|
存储 安全 Java
java多线程之原子操作类
java多线程之原子操作类
|
10天前
|
Java
Java中的多线程实现:使用Thread类与Runnable接口
【4月更文挑战第8天】本文将详细介绍Java中实现多线程的两种方法:使用Thread类和实现Runnable接口。我们将通过实例代码展示如何创建和管理线程,以及如何处理线程同步问题。最后,我们将比较这两种方法的优缺点,以帮助读者在实际开发中选择合适的多线程实现方式。
19 4
|
11天前
|
Java
在Java中,多态性允许不同类的对象对同一消息做出响应
【4月更文挑战第7天】在Java中,多态性允许不同类的对象对同一消息做出响应
16 2