上一篇地址:整理好了!2024年最常见 100 道 Java基础面试题(二十五)-CSDN博客
五十一、String 类的常用方法都有那些?
String
类在 Java 中是一个非常强大和常用的类,提供了多种方法来操作字符串。以下是一些 String
类的常用方法:
-
length()
- 返回字符串的长度。 -
charAt(int index)
- 返回指定索引处的字符。 -
substring(int beginIndex)
- 返回一个新字符串,它是原字符串从指定位置开始的子串。 -
substring(int beginIndex, int endIndex)
- 返回一个新字符串,它是原字符串从beginIndex
到endIndex - 1
的子串。 -
equals(Object another)
- 检查字符串是否与另一个对象相等。 -
equalsIgnoreCase(String another)
- 检查字符串是否与另一个字符串相等,忽略大小写。 -
startsWith(String prefix)
- 检查字符串是否以指定的前缀开始。 -
endsWith(String suffix)
- 检查字符串是否以指定的后缀结束。 -
contains(CharSequence s)
- 检查字符串是否包含指定的字符序列。 -
indexOf(int ch)
- 返回指定字符在字符串中第一次出现的索引。 -
indexOf(String str)
- 返回指定字符串在原字符串中第一次出现的索引。 -
lastIndexOf(int ch)
- 返回指定字符在字符串中最后一次出现的索引。 -
concat(String str)
- 将指定字符串连接到原字符串的结尾。 -
replace(char oldChar, char newChar)
- 返回一个新的字符串,其中所有出现的oldChar
都被newChar
替换。 -
replaceAll(String regex, String replacement)
- 使用给定的replacement
替换字符串中所有匹配regex
的子串。 -
replaceFirst(String regex, String replacement)
- 使用给定的replacement
替换字符串中第一个匹配regex
的子串。 -
toLowerCase()
- 将字符串转换为小写。 -
toUpperCase()
- 将字符串转换为大写。 -
trim()
- 返回一个新字符串,移除原字符串两端的空白字符。 -
split(String regex)
- 根据匹配给定的正则表达式regex
来拆分字符串。 -
valueOf(Object obj)
- 返回一个字符串,表示obj
的字符串表示形式。 -
toString()
- 返回字符串本身(String
类重写了Object
类的toString()
方法)。
示例
String str = "Hello, World!";
int length = str.length(); // 13
String sub = str.substring(0, 5); // "Hello,"
boolean startsWithH = str.startsWith("Hello"); // true
boolean containsWorld = str.contains("World"); // true
String lower = str.toLowerCase(); // "hello, world!"
String upper = str.toUpperCase(); // "HELLO, WORLD!"
String replaced = str.replace("World", "Java"); // "Hello, Java!"
注意事项
String
类中的很多方法都返回新的String
对象,因为String
对象是不可变的。- 字符串操作可能会导致性能问题,尤其是在处理大量数据时,应该注意字符串操作的性能影响。
总结
String
类提供了丰富的方法来处理字符串,这些方法可以用于字符串的比较、查找、替换、转换大小写、拆分和连接等操作。了解这些常用方法对于日常的字符串处理任务非常重要。
五十二、String 的底层实现是怎样的?
在Java中,String
对象的底层实现历经了多个版本的变迁,但主要是基于字符数组或类似数组的结构来存储字符串数据。以下是String
对象底层实现的一些关键点:
1. 不可变性
String
对象在Java中是不可变的(Immutable)。这意味着一旦一个String
对象被创建,它的内容就不能被改变。任何修改操作都会产生一个新的String
对象。
2. 字符数组
在Java 8及以前的版本中,String
类的内部通常使用一个char
数组来存储字符串数据:
public final class String {
private final char value[];
// ... 其他代码
}
这里的value[]
是一个字符数组,用于存储字符串的字符序列。
3. 压缩的String
(Java 9+)
从Java 9开始,为了节省内存,String
类的实现采用了一种新的存储结构。如果字符串只包含拉丁字符(如ASCII),则底层结构会使用byte
数组加上一个表示每个字节编码多少个字符的标志位(coder
)。对于包含非拉丁字符的字符串,仍然使用char
数组。
public final class String {
private final byte[] value;
private final byte coder;
// ... 其他代码
}
在这个结构中,coder
的值可以是:
LATIN1
:表示value
是一个Latin-1 (ISO-8859-1) 编码的字节数组。UTF16
:表示value
是一个标准的char
数组。
4. 字符串常量池
在Java中,字符串常量会被存储在字符串常量池中。字符串常量池是一个特殊的存储区域,用于存储在程序中多次出现的字符串字面量,以节省内存。
5. 字符串的创建
当通过字符串字面量或String
构造函数创建字符串时,Java虚拟机会首先检查字符串常量池中是否已经存在一个相同的字符串对象。如果存在,就会返回那个对象的引用;如果不存在,就会在常量池中创建一个新的String
对象。
示例
String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2); // 输出 true,因为它们引用常量池中的同一个对象
注意事项
- 由于
String
的不可变性,频繁修改字符串(如在循环中拼接字符串)可能会导致性能问题和内存浪费。在这种情况下,推荐使用StringBuilder
或StringBuffer
。 - 字符串的不可变性也意味着它是线程安全的,不需要额外的同步措施就可以在多线程环境中使用。
总结
String
类的底层实现细节随着Java版本的更新而有所变化,但其核心概念保持不变。理解String
的不可变性、存储结构和字符串常量池对于编写高效的Java程序非常重要。