在 Java 中,字符串是不可变的,但频繁创建大量字符串对象会占用较多内存。通过使用 String.intern() 方法,可以将字符串加入 JVM 的字符串池(String Pool),以节省内存和提高性能。
String.intern()的作用
intern() 方法会检查字符串池中是否已有当前字符串:
- 如果有,则返回池中的引用。
- 如果没有,则将字符串添加到池中,并返回这个字符串的引用。
代码示例
未使用 intern() 的场景
public class WithoutIntern {public static void main(String[] args) {String str1 = new String("hello");String str2 = new String("hello");System.out.println(str1 == str2); // false,因为是两个不同的对象}
}
使用 intern() 的场景
public class WithIntern {public static void main(String[] args) {String str1 = new String("hello").intern();String str2 = new String("hello").intern();System.out.println(str1 == str2); // true,因为引用指向了同一个池中的对象}
}
使用场景
重复字符串
在大量重复字符串的场景中(如日志处理、数据解析),intern() 可以显著节省内存。
public class StringInternExample {public static void main(String[] args) {String[] data = {"apple", "banana", "apple", "orange", "banana"};for (int i = 0; i < data.length; i++) {data[i] = data[i].intern(); // 将字符串放入池中}System.out.println(data[0] == data[2]); // trueSystem.out.println(data[1] == data[4]); // true}
}
性能优化
如果某些操作需要频繁比较字符串,可以通过 intern() 确保字符串引用相等,提升性能
注意事项
- 内存管理
字符串池是 JVM 的一种全局内存区域,过多使用 intern() 可能导致字符串池过大,影响垃圾回收。
- JVM 字符串池的变化
在 Java 6 及之前,字符串池位于永久代(PermGen),空间有限。
从 Java 7 开始,字符串池被移到了堆内存(Heap),大小由堆大小决定。
- 不是万能的
如果字符串本身变化较多(如动态拼接生成的大量字符串),频繁使用 intern() 可能带来额外开销。
常见问题
Q: intern() 适合所有场景吗?
不适合:对于短生命周期的字符串或唯一性字符串(如 UUID),不推荐使用 intern()。
Q: 字符串池中的对象会被 GC 吗?
是的,字符串池中的对象在没有其他引用时可以被垃圾回收。
总结
通过使用 String.intern(),你可以有效减少内存占用并提升字符串操作的性能,但要谨慎选择使用场景,避免因不当使用而导致内存管理问题。这是一个冷门但强大的优化技巧,特别适合处理大量重复字符串的场景!