前言
Java 的 String
类是最常用的类之一,但其底层实现和特性往往容易被忽视。以下是 String
类的重点解析,涵盖核心概念、内存管理、性能优化及常见问题。
String
类的核心特点
String
是 Java 中用于处理字符串的类,位于 java.lang
包下,无需手动导入。以下是其主要特点:
不可变性(Immutability)
String
对象一旦创建,其内容无法修改。任何看似修改字符串的操作(如拼接、替换)实际上都会创建一个新的 String
对象。这种设计带来了线程安全性和内存优化的好处,但也需要注意性能问题(例如频繁拼接时建议使用 StringBuilder
)。
示例:
1 | String s1 = "Hello"; |
字符串的创建方式与内存分配
Java 维护了一个字符串常量池,用于存储字符串字面量。例如,String s1 = "hello"; String s2 = "hello";
中,s1
和 s2
指向常量池中的同一个对象。这种机制减少了内存占用,但通过 new String("hello")
创建的字符串会在堆中分配新对象。
- 字面量赋值:直接使用双引号。检查字符串常量池,存在则附庸,否则新建并缓存。
new
关键字:强制在堆中创建新对象,不检查常量池。
字符串常量池(String Pool)是 JVM 维护的一块特殊内存区域,存储唯一字符串字面量。
基于字符数组实现
在 JDK 8 及之前,String
内部使用 char[]
存储字符数据。从 JDK 9 开始,改为使用 byte[]
加上编码标志,以更高效地存储字符串(支持 Latin-1 和 UTF-16 编码)。
final
类
String
类被声明为 final
,无法被继承。这种设计确保了其不可变性和安全性。
构造方法
String
类提供了多种构造方法,以下是常见的几种:
String()
:创建一个空字符串。String(String original)
:通过已有字符串创建新字符串。String(char[] value)
:通过字符数组创建字符串。String(byte[] bytes, Charset charset)
:通过字节数组和指定字符集创建字符串。
示例:
1 | String s1 = new String(); // "" |
常用方法
String
类提供了丰富的操作方法,以下按功能分类介绍:
获取信息
length()
:返回字符串长度。charAt(int index)
:返回指定索引处的字符(索引从 0 开始)。isEmpty()
:判断字符串是否为空。
示例:
1 | String str = "Hello, Java"; |
比较
equals(Object obj)
:比较两个字符串内容是否相等(区分大小写)。equalsIgnoreCase(String another)
:忽略大小写比较。compareTo(String another)
:按字典序比较,返回正数、负数或 0。
示例:
1 | String s1 = "java"; |
查找与定位
indexOf(int ch/String str)
:返回字符或子串首次出现的位置,未找到返回 -1。lastIndexOf(int ch/String str)
:返回最后一次出现的位置。contains(CharSequence s)
:判断是否包含指定子串。
示例:
1 | String str = "Hello, Java"; |
修改(返回新字符串)
substring(int beginIndex)
:从指定索引截取到末尾。substring(int beginIndex, int endIndex)
:截取指定范围(不包含 endIndex)。replace(char oldChar, char newChar)
:替换所有指定字符。trim()
:去除首尾空白字符。
示例:
1 | String str = " Hello, Java "; |
分割与连接
split(String regex)
:按正则表达式分割字符串,返回字符串数组。join(CharSequence delimiter, CharSequence... elements)
:(JDK 8+)用分隔符连接多个字符串。
示例:
1 | String str = "a,b,c"; |
格式化
format(String format, Object... args)
:格式化字符串。valueOf(Object obj)
:将对象转换为字符串。
示例:
1 | String formatted = String.format("Name: %s, Age: %d", "Alice", 25); |
性能与注意事项
字符串拼接
使用 +
拼接字符串在循环中会导致性能问题,因为每次拼接都会创建新对象。推荐使用 StringBuilder
或 StringBuffer
:
1 | StringBuilder sb = new StringBuilder(); |
==
vs equals()
==
比较的是引用是否相同,而 equals()
比较内容是否相同:
1 | String s1 = "hello"; |
常量池与 intern()
调用 intern()
方法可以将字符串放入常量池,并返回常量池中的引用(谨慎使用,可能引发 Full GC):
1 | String s1 = new String("hello").intern(); |
后记
String
类是 Java 中最常用的类之一,其不可变性、常量池机制和丰富的 API 使其在字符串处理中非常强大。