Java String类深度解析:从特性到实战避坑
、String类的核心特性:不可变性
String类最核心的特性就是不可变性,即一旦一个String对象被创建,它的值就无法被修改。很多同学可能会有疑问:我们平时写的String str = "abc"; str = "def";不是修改了字符串吗?其实不然,这里的“修改”本质上是让str变量重新指向了一个新的String对象"def",而原来的"abc"对象并没有被改变,最终会被垃圾回收器回收。
那么String的不可变性是如何实现的呢?我们来看JDK源码(以JDK 8为例):

从源码可以看出,String类被final修饰,意味着它不能被继承;同时,存储字符串数据的value数组也是final修饰的,这保证了value数组的引用地址无法被修改。虽然value数组本身是可以修改的(比如通过反射),但Java官方并未提供这样的接口,因此从开发者的角度来看,String对象就是不可变的。
不可变性带来了很多优势:首先是线程安全,由于String对象无法被修改,多线程环境下使用无需担心线程安全问题;其次是可以实现字符串常量池复用,减少内存占用;此外,不可变性还让String对象的哈希值可以被缓存,提升了哈希表等集合的性能。
二、String对象的创建方式:常量池vs堆内存
Java中创建String对象主要有两种方式,这两种方式的底层实现和内存分配完全不同,也是面试中的高频考点。
1. 直接赋值方式(常量池)
当我们使用String str = "abc";这种方式创建对象时,JVM会先去字符串常量池中查找是否存在"abc"这个字符串。如果存在,直接将常量池中的对象引用赋值给str;如果不存在,就会在常量池中创建一个"abc"对象,再将引用赋值给str。
2. new关键字方式(堆内存)
当使用String str = new String("abc");创建对象时,JVM会先在堆内存中创建一个String对象,然后去字符串常量池中查找是否存在"abc"。如果常量池中没有"abc",会先在常量池中创建一个"abc"对象,再将堆内存中对象的value数组指向常量池中的value数组;最后将堆内存中对象的引用赋值给str。也就是说,这种方式至少会创建一个对象,最多会创建两个对象(常量池不存在时)。
我们通过一个简单的例子来验证:

这里要注意:==运算符比较的是对象的引用地址,而String类重写了equals方法,比较的是字符串的实际内容。因此,在比较字符串内容时,一定要使用equals方法,而不是==。
三、String类的常用方法实战
String类提供了大量实用的方法,下面介绍几个开发中最常用的方法及使用注意事项。
1. 字符串拼接:+ 运算符vs concat方法
字符串拼接是最常见的操作,我们可以使用+运算符或concat方法。需要注意的是,由于String的不可变性,每次拼接都会创建一个新的String对象,效率较低。
示例:
String str1 = "a";
String str2 = str1 + "b"; // 创建新对象"ab"
String str3 = str2.concat("c"); // 创建新对象"abc"
如果需要大量拼接字符串,建议使用StringBuilder(非线程安全,效率高)或StringBuffer(线程安全,效率稍低),它们的底层是可变的字符数组,不会频繁创建新对象。
2. 字符串查找:indexOf vs contains
indexOf方法用于查找指定字符或字符串在当前字符串中的索引位置,若不存在则返回-1;contains方法用于判断当前字符串是否包含指定字符序列,其底层其实就是调用indexOf方法实现的。
示例:
String str = "Hello Java"; System.out.println(str.indexOf("Java")); // 6 System.out.println(str.indexOf("Python")); // -1 System.out.println(str.contains("Java")); // true
3. 字符串截取:substring
substring方法用于截取字符串的一部分,有两个重载方法:substring(int beginIndex)(从beginIndex开始截取到末尾)和substring(int beginIndex, int endIndex)(截取[beginIndex, endIndex)区间的字符串,左闭右开)。
示例:
String str = "Hello Java";
System.out.println(str.substring(6)); // Java
System.out.println(str.substring(0, 5)); // Hello
4. 字符串转换:toLowerCase vs toUpperCase vs valueOf
toLowerCase和toUpperCase方法分别用于将字符串转换为小写和大写;valueOf方法是静态方法,用于将其他类型(如int、boolean、Object等)转换为String类型,非常常用。
更多推荐




所有评论(0)