前言
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 使其在字符串处理中非常强大。