Java 字符串

2025年3月22日 | 阅读 12 分钟

Java 中,字符串本质上是一个表示字符序列的对象。字符数组在 Java 中充当字符串。例如:

与...相同

Java String 类提供了许多方法来执行字符串操作,例如 compare()、concat()、equals()、split()、length()、replace()、compareTo()、intern()、substring() 等。

java.lang.String 类实现了 SerializableComparableCharSequence 接口

String in Java

CharSequence 接口

CharSequence 接口用于表示字符序列。String、StringBufferStringBuilder 类都实现了它。这意味着,我们可以使用这三个类在 Java 中创建字符串。

CharSequence in Java

Java String 是不可变的,意味着它不能被更改。每次更改字符串时,都会创建一个新实例。对于可变字符串,您可以使用 StringBuffer 和 StringBuilder 类。

稍后我们将讨论不可变字符串。首先,让我们了解 Java 中的 String 是什么以及如何创建 String 对象。

Java 中的 String 是什么?

通常,String 是一个字符序列。但在 Java 中,String 是一个表示字符序列的对象。java.lang.String 类用于创建 String 对象。

如何创建 String 对象?

有两种创建 String 对象的方法:

  1. 通过字符串字面量
  2. 通过 new 关键字

1) String 字面量

Java 字符串字面量是通过双引号创建的。例如

每次创建字符串字面量时,JVM 会先检查“字符串常量池”。如果字符串已存在于池中,则返回池中实例的引用。如果字符串不存在于池中,则创建一个新的字符串实例并放入池中。例如:


Java String

在上面的示例中,只创建了一个对象。首先,JVM 在字符串常量池中找不到值为“Welcome”的字符串对象,因此它会创建一个新对象。之后,它会在池中找到值为“Welcome”的字符串,它不会创建新对象,而是返回同一实例的引用。

示例

编译并运行

输出

Welcome Welcome

注意:String 对象存储在一个称为“字符串常量池”的特殊内存区域。

为什么 Java 使用 String 字面量的概念?

为了使 Java 更节省内存(因为如果字符串已存在于字符串常量池中,则不会创建新对象)。

2) 通过 new 关键字

在这种情况下,JVM 将在常规(非池)堆内存中创建一个新的字符串对象,并且字面量“Welcome”将被放入字符串常量池中。变量 s 将引用堆(非池)中的对象。

示例

编译并运行

输出

Welcome Welcome

Java String 类

String 类是 Java 中最基本的类型之一,旨在表示不可变的字符序列。以下是其特性和实现接口的详细介绍:

  • 不可变性: 一旦实例化,String 对象就无法修改。这种不可变设计是刻意为之,以确保线程安全、一致性和效率,尤其是在 String 池机制方面。
  • 字符串池: Java 维护一个字符串字面量池,以帮助节省内存。当创建一个新的字符串字面量时,Java 会在池中查找匹配的字符串。如果找到,新变量将引用池中的字符串。如果找不到,新字符串将被添加到池中。
  • 实现的接口: String 类实现了多个接口,包括:
    • Serializable: 允许将字符串对象序列化为字节流,便于传输或存储。
    • Comparable<String>: 支持两个字符串之间的字典序比较,支持集合中的自然排序。
    • CharSequence: 为不同类型的字符序列提供统一的只读接口,允许String 对象被通用地操作和访问。

CharSequence 接口

Java 的 CharSequence 接口提供了一个统一的、只读的字符序列视图,并且是 java.lang 包的一部分。它促进了各种字符序列(包括 String、StringBuilder、StringBuffer 和 CharBuffer)之间的统一访问和操作。通过此接口,定义了处理字符数据的关键功能,实现了测量序列长度、访问特定字符、生成字符子序列以及转换为 String 格式等操作。通过为字符序列提供通用蓝图,`CharSequence` 实现了 Java 平台中灵活且与实现无关的文本处理。

  1. String
  2. StringBuffer
  3. StringBuilder

String

在 Java 中,String 类封装了一系列字符。一旦实例化,String 对象的内容就是固定的,无法修改,这归功于其不可变性。这种不可变性确保了 String 对象在多个线程之间可以安全地并发使用,并且在文本内容保持不变的情况下具有最佳性能。为了提高内存效率,Java 采用了一种称为字符串驻留(string interning)的技术。这种方法优化了常用字符串字面量的存储和访问。

语法

通过字符串字面量直接赋值

使用 String 构造函数

文件名: StringExample.java

输出

Hello, World!
Length: 13

StringBuffer

StringBuffer 代表一个可变的字符序列,可确保线程安全,使其适用于需要多个线程修改字符序列的场景。它包含各种字符串操作功能,包括插入、删除和追加字符的能力。这种设计避免了每次更改时都生成新对象的需要,从而在需要频繁调整字符串内容的情况下提高了效率。

语法

文件名: StringBufferExample.java

输出

Hello, World!

StringBuilder

StringBuilder 与 StringBuffer 类似,也是一个可变的字符序列。关键的区别在于 StringBuilder 不同步,因此不适用于线程安全操作。然而,这种缺乏同步的特性使得 StringBuilder 在单线程或特定线程环境中提供了更高的性能。因此,在并发线程访问安全性不是问题的环境中,StringBuilder 成为操作字符串的首选选项。

语法

文件名: StringBuilderExample.java

输出

Hello, World!

Java 中的不可变 String

在 Java 中,字符串是不可变的。这意味着一旦创建了 String 对象,其值就无法更改。如果任何操作似乎修改了 String,实际发生的是创建了一个新的 String 对象。原始字符串保持不变。Java 中字符串的这种不可变特性对性能、安全性和功能有多种影响。

文件名: ImmutableStringExample.java

输出

Original string: Java
After modification, original string: Java
Modified string: Java Programming
After calling toUpperCase on original string: Java
Original string in uppercase: JAVA

String 的内存分配

Java 中字符串的内存分配很有趣,因为它涉及到 Java 对字符串不可变性的处理和字符串池机制。了解字符串的存储方式可以帮助优化 Java 应用程序的内存使用,尤其是那些大量使用字符串操作的应用程序。

字符串字面量存储: 当您使用字符串字面量创建字符串时,Java 会先检查字符串池。如果字符串已存在,新变量将指向现有字符串。如果不存在,新字符串将被添加到池中,变量将指向这个新字符串。

语法

new 关键字和字符串池: 使用 new 运算符创建的字符串默认不使用池。它们存储在池外部的堆内存中,这意味着每次 new 操作都会生成一个新对象,即使它包含相同的数据。

语法

驻留(Interning): 我们可以通过在字符串对象上调用 intern() 方法来手动将字符串添加到池中或确保其使用池。如果池中已包含相等的字符串,则返回池中的字符串。否则,将该字符串添加到池中。

语法

文件名: StringMemoryAllotment.java

输出

str1 == str2: true
str3 == str4: false
str1 == str5: true
str1 == str6: true

从 char 数组的子集构建 String

在 Java 中,可以通过 String 类中的特定构造函数,基于 char 数组的一部分来创建 String。此构造函数需要三个参数:要使用的 char 数组、表示所需子集起始点的索引,以及要包含在子集中的字符数。以下是语法和示例:

语法

  • value: char 数组。
  • offset: 数组中的初始偏移量。
  • count: 要从数组中使用的字符数。

文件名: CharArrayToString.java

输出

World

让我们看另一个使用 char[] 数组创建的 Java String 示例。

StringExample.java

输出

java
strings
example

上面的代码将一个 char 数组转换为一个 String 对象。并使用 println() 方法在控制台上显示 String 对象 s1、s2s3

Java String 选择题

1. 在 Java 中,可以使用哪个方法按字典序比较两个字符串?

  1. compareTo()
  2. equals()
  3. compare()
  4. equalsIgnoreCase()
 

答案:a)

解释: compareTo() 方法按字典序比较两个字符串。如果第一个字符串在第二个字符串之前,则结果为负整数;如果字符串相等,则结果为零;如果第一个字符串在第二个字符串之后,则结果为正整数。


2. 以下代码的输出是什么?

  1. Java
  2. JavaPoint
  3. Java Point
  4. 要点
 

答案:a)

解释: Java 中的字符串是不可变的。concat() 方法会创建一个新的字符串,但不会改变原始字符串。因此,原始字符串 s 仍然是“Java”。


3. 如何在 Java 中从字符数组创建新的字符串对象?

  1. new String(chars)
  2. String.valueOf(chars)
  3. String.copyValueOf(chars)
  4. 以上全部。
 

答案:d)

解释: 以上所有列出的方法都可以从字符数组创建新的字符串。new String(chars)、String.valueOf(chars) 和 String.copyValueOf(chars) 是实现此目的的不同方式。


4. 在 Java 中,使用哪个方法将字符串中的所有字符转换为小写?

  1. toLowerCase()
  2. toLower()
  3. toLowerCase(Locale locale)
  4. a and c
 

答案:d)

解释: toLowerCase() 方法使用默认区域设置将字符串中的所有字符转换为小写。toLowerCase(Locale locale) 方法使用指定的区域设置将所有字符转换为小写。


5. 以下代码的结果是什么?

  1. " Hello World "
  2. "Hello World"
  3. "Hello World "
  4. " Hello World"
 

答案:b)

解释: trim() 方法会删除字符串开头和结尾的空格,因此输出是“Hello World”。


你知道吗?
  • 为什么 String 对象是不可变的?
  • 如何创建不可变类?
  • 什么是字符串常量池?
  • 如果使用 +(字符串连接运算符)连接任何字符串,编译器会写入什么代码?
  • StringBuffer 和 StringBuilder 类有什么区别?
 
在字符串处理中,我们将学到什么?
  • String 的概念
  • 不可变 String
  • 字符串比较
  • 字符串连接
  • 子字符串的概念
  • String 类方法及其用法
  • StringBuffer 类
  • StringBuilder 类
  • 创建不可变类
  • toString() 方法
  • StringTokenizer 类