Java String类核心用法与底层原理详解
Java中的String类是开发中最基础也最重要的组件之一。掌握其常用API不仅能提高代码效率,理解其底层不可变性与常量池机制更是避免内存泄漏和性能瓶颈的关键。本文将从实际操作出发,系统梳理String的核心功能。
一、String常用核心API
第1步:创建字符串实例
String对象可以通过直接赋值或构造器创建。直接赋值会检查常量池,而new关键字则强制在堆内存中创建新对象。
// 直接赋值:优先使用,若常量池中存在相同字符串则复用引用
String str = "abc";
// 构造器方式:char数组或字符串转义
char[] charArray = {'a', 'b', 'c'};
String str1 = new String("abc");
String str2 = new String(str1);
String str3 = new String(charArray);
第2步:获取长度与指定位置字符
使用length()获取字符数,charAt(index)获取特定索引的字符。索引从0开始。
String str = "abcdef";
int length = str.length(); // 结果为6
char ch = str.charAt(4); // 结果为'e',索引4对应第5个字符
第3步:提取子串
substring方法用于截取字符串部分。注意第二个参数endIndex是不包含在内的左闭右开区间。
String source = "abcdef";
// 从索引2开始直到末尾:"cdef"
String sub1 = source.substring(2);
// 从索引2到索引5(不含5):"cde"
String sub2 = source.substring(2, 5);
第4步:字符串比较
区分内容比较与引用比较。equals比较实际字符序列,compareTo按字典序比较大小。
String s1 = "abc";
String s2 = "ABC";
// 忽略大小写比较:返回true
boolean eq = s1.equalsIgnoreCase(s2);
// 字典序比较:'a' (97) - 'A' (65) > 0,返回正整数
int cmp = s1.compareTo(s2);
// 忽略大小写的字典序比较:返回0
int cmpIgnore = s1.compareToIgnoreCase(s2);
第5步:字符串连接
虽然可以使用+号拼接,但concat方法明确用于将参数字符串追加到当前字符串后。
String result = "aa".concat("bb").concat("cc");
// 等价于 "aa" + "bb" + "cc",结果为"aabbcc"
第6步:查找子串或字符位置
indexOf系列方法用于定位。找到返回首次出现的索引,未找到返回-1。lastIndexOf反向搜索。
String text = "I really miss you !";
// 正向查找'a'的位置:4
int pos1 = text.indexOf('a');
// 从索引2开始正向查找'really':2
int pos2 = text.indexOf("really");
// 反向查找's',从索引7开始向前找:7
int pos3 = text.lastIndexOf('s', 7);
// 未找到返回-1
int pos4 = text.indexOf("gg", 2);
第7步:大小写转换
toLowerCase和toUpperCase生成新的字符串对象,原字符串不变。
String mix = "abCD";
String lower = mix.toLowerCase(); // "abcd"
String upper = mix.toUpperCase(); // "ABCD"
第8步:替换字符或子串
replace替换所有匹配项,replaceFirst只替换第一个,replaceAll支持正则表达式。
String s = "asdzxcasd";
// 替换单个字符:所有'a'变为'g'
String r1 = s.replace('a', 'g'); // "gsdzxcgsd"
// 替换子串:所有"asd"变为"fgh"
String r2 = s.replaceAll("asd", "fgh"); // "fghzxcfgh"
// 仅替换第一次出现
String r3 = s.replaceFirst("asd", "fgh"); // "fghzxcasd"
第9步:清理空格与分割字符串
trim去除首尾空格;split根据正则表达式分割字符串为数组。
String spaced = " a bc ";
String trimmed = spaced.trim(); // 结果"a bc",长度为4
String csv = "abc,def,ghi";
// 以逗号分割
String[] parts = csv.split(","); // ["abc", "def", "ghi"]
第10步:数据类型转换
基本类型与字符串互转涉及Integer、Float等包装类的静态方法。
// 字符串转数值
int n = Integer.parseInt("12");
double d = Double.parseDouble("1.124");
// 数值转字符串
String strNum = String.valueOf(n);
// 进制转换示例
String hex = Long.toHexString(15); // "f" (十六进制)
String bin = Long.toBinaryString(10); // "1010" (二进制)
二、String特性与底层机制
理解String的底层行为对于写出高效Java代码至关重要,主要涉及不可变性、常量池以及引用比较。
1. 不可变性 (Immutability)
String类被声明为final,且内部字符数组也是final的。这意味着一旦String对象创建,其内容无法修改。所有的"修改"操作(如concat、replace)实际上都是返回一个新的String对象。这保证了线程安全和哈希值稳定。
2. 字符串常量池 (String Constant Pool)
JVM维护一个字符串常量池。当使用直接赋值(如 String s = "abc";)时,JVM会先检查常量池中是否存在该字符串。若存在,直接返回引用;若不存在,则在池中创建并返回引用。
- 编译期确定: 由纯字符串常量组成的拼接(如
"a" + "b"),编译器会在class文件加载前优化为一个常量字符串存入常量池。 - 运行期确定: 涉及变量或new关键字的拼接(如
s1 + "b"或new String("abc")),会在堆内存中创建新对象,不直接进入常量池。
3. intern() 方法的作用
String.intern() 是一个Native方法。它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回池中的字符串引用;否则,将此String对象添加到常量池中,并返回引用。
String s1 = new String("hello");
String s2 = s1.intern();
// s1在堆中,s2在常量池中(假设之前没有字面量"hello")
// 此时 s2 == "hello" (字面量引用)
4. == 与 equals 的区别
- ==: 比较的是栈内存中的引用地址是否相同。对于对象,只有当它们是同一个实例时才为true。
- equals: String重写了Object的equals方法,比较的是两个字符串的内容(字符序列)是否一致。
三、StringBuffer 与 StringBuilder
由于String是不可变的,频繁的字符串拼接会产生大量临时对象,导致内存浪费和GC压力。此时应使用可变字符串缓冲区。
| 类名 | 线程安全 | 性能 | 适用场景 |
|---|---|---|---|
| String | 是 | 低(频繁修改时) | 少量拼接,常量定义 |
| StringBuilder | 否 | 高 | 单线程环境下的大量字符串操作 |
| StringBuffer | 是 | 中等 | 多线程环境下的字符串操作 |
常用操作:
append(data):追加数据,始终添加到末尾。insert(index, data):在指定位置插入数据。delete(start, end):删除指定范围的数据。reverse():反转字符串顺序。
以上就是java.lang.String类使用的详细内容,更多关于Java字符串优化的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









