前言
Java 中的 String 类是面试中经常被问到的话题,因为它不仅是最常用的类之一,而且有许多特性和优化值得深入理解。以下是一些常见的 String 类面试问题及解答。
String 的不可变性
问题:为什么 String 类在 Java 中是不可变的?
String 类在 Java 中被设计为不可变的,主要有以下几个原因:
- 安全性:
String经常用于存储敏感信息如用户名、密码等,不可变性确保这些值不会被意外修改。 - 线程安全:不可变对象天然是线程安全的,可以被多个线程共享使用。
- 字符串池优化:Java 维护一个字符串常量池,可以重用
String对象,节省内存。 - 哈希缓存:
String对象被广泛用作HashMap的键,不可变性确保哈希值不变,提高性能。
String,StringBuilder 和 StringBuffer
问题:String,StringBuilder 和 StringBuffer 的区别是什么?
- **
String**:不可变,线程安全,每次操作都会创建新对象。 - **
StringBuilder**:可变,非线程安全,适合单线程环境下的字符串操作,性能最好。 - **
StringBuffer**:可变,线程安全(方法使用synchronized修饰),适合多线程环境下的字符串操作。
何时使用哪个?
- 如果字符串不会改变,使用
String。 - 如果字符串会频繁修改且在单线程环境,使用
StringBuilder。 - 如果字符串会频繁修改且在多线程环境,使用
StringBuffer。
字符串常量池
问题:解释一下Java中的字符串常量池
字符串常量池是 JVM 中的一个特殊内存区域,用于存储字符串字面量。当创建字符串字面量时,JVM 首先检查池中是否已有相同的字符串:
- 如果存在,则返回对池中对象的引用。
- 如果不存在,则在池中创建新的字符串对象并返回其引用。
1 | String s1 = "hello"; // 创建一个字符串,存储在常量池中 |
问题:new String("abc") 创建了几个对象?
若常量池中无
"abc":1 个放入常量池,1 个堆对象 → 共 2 个。若常量池中已有
"abc":仅创建 1 个堆对象。
intern() 方法
问题:String 类的 intern() 方法有什么作用?
intern() 方法用于将字符串对象添加到字符串常量池中:
- 如果池中已存在该字符串,则返回池中的字符串对象。
- 如果池中不存在,则添加到池中并返回其引用。
1 | String s1 = new String("hello"); // 在堆内存中创建对象 |
equals() 和 == 的区别
问题:在比较 String 时,equals() 和 == 有什么区别?
==运算符:比较引用是否指向同一对象(比较内存地址)equals()方法:比较字符串的内容是否相同(String类重写了Object的equals方法)
1 | String s1 = "Hello"; |
性能优化相关问题
问题:在循环中进行大量字符串拼接操作应该使用什么方法?
在循环中使用 + 进行字符串拼接会创建大量临时对象,影响性能。应该使用 StringBuilder:
1 | // 低效方式 |
问题:String str = "a" + "b" + "c"; 在内存中如何操作?
编译期优化:字面量拼接会被编译器直接合并为 "abc",只生成一个常量。
运行时拼接(如循环中使用 +):每次拼接生成新 String 对象,效率低。应改用 StringBuilder。
String 的内存占用
问题:String 对象在内存中占用多少空间?
在 Java 8 及之前版本中,String 内部使用 char[] 数组存储字符,每个字符占 2 字节。Java 9 之后改用 byte[] 数组加编码标记,可以根据字符内容采用 Latin-1(1字节/字符)或 UTF-16(2字节/字符)编码,以减少内存占用。
常见的 String 方法
问题:列举一些常用的 String 方法及其用途
length():返回字符串长度charAt(int index):返回指定索引处的字符substring(int beginIndex, int endIndex):返回子字符串equals(Object anObject):比较字符串内容equalsIgnoreCase(String anotherString):忽略大小写比较字符串startsWith(String prefix)/endsWith(String suffix):检查前缀/后缀indexOf(String str):查找子字符串第一次出现的位置replace(CharSequence target, CharSequence replacement):替换所有匹配的子字符串trim():去除前导和尾随空白split(String regex):按正则表达式分割字符串toLowerCase()/toUpperCase():转换为小写/大写
字符串比较和排序
问题:如何比较和排序字符串?
- **
compareTo(String anotherString)**:按字典顺序比较两个字符串 - **
compareToIgnoreCase(String str)**:忽略大小写按字典顺序比较
1 | String[] names = {"张三", "李四", "王五"}; |
字符串格式化
问题:如何格式化字符串?
使用 String.format() 方法或 printf() 方法:
1 | String formatted = String.format("姓名: %s, 年龄: %d", "张三", 25); |
String 与其他数据类型的转换
问题:如何在 String 和其他数据类型之间进行转换?
1 | // 基本类型转String |
后记
理解 String 类及其相关类的特性和优化对于 Java 程序员至关重要。面试中,不仅要了解基本用法,还要理解底层原理,如不可变性、字符串常量池、性能优化等方面的知识。