引入
我们之前学过:Java 里 everything is object,所有类都属于某个包。同一个项目里可能出现同名类,为了不混淆,就要用 全类名(包名 + 类名) 来唯一确定一个类。
之前我们写过:
public class Student { ... }
这个 Student 就是一个类,我们可以创建对象:
Student stu = new Student();
而**String 也是一个类** ,和 Student 本质一样,只是它是 Java 官方提前写好的类。
它所在的包是 java.lang,所以它的全类名就是:
java.lang.String
就像我们用 Scanner 要写 java.util.Scanner 一样,String 也有自己完整的 "全名",只是因为 java.lang 包默认自动导入 ,我们平时可以直接简写为 String。
简单总结一句:String 就是一个和我们自己写的 Student 一样的引用类型类,只是它是系统自带的,全名是 java.lang.String。
1. String 常用方法
1.1 字符串三种构造方式
String 提供了非常多的构造方式,最常用的就 3 种:
public static void main(String[] args) {
// 1. 使用常量串构造(最常用)
String s1 = "hello bit";
System.out.println(s1);
// 2. 直接 new String 对象
String s2 = new String("hello bit");
System.out.println(s2);
// 3. 使用字符数组构造
char[] array = {'h','e','l','l','o','b','i','t'};
String s3 = new String(array);
System.out.println(s3);
}
1.2 String 对象的四种比较方式
1)== 比较:比地址
-
基本类型:== 比值
-
引用类型:== 比地址
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = s1;System.out.println(s1 == s2); // false(地址不同) System.out.println(s1 == s3); // true(地址相同)}
2)equals ():比内容(最常用)
String 重写了 Object 的 equals(),按字符逐个比较内容。
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("Hello");
System.out.println(s1.equals(s2)); // true
System.out.println(s1.equals(s3)); // false
}
3)compareTo ():按字典序比大小(返回 int)
public static void main(String[] args) {
String s1 = "abc";
String s2 = "ac";
String s3 = "abcdef";
System.out.println(s1.compareTo(s2)); // -1
System.out.println(s1.compareTo(s3)); // -3
}
4)compareToIgnoreCase ():忽略大小写比较
String s1 = "abc";
String s2 = "ABC";
System.out.println(s1.compareToIgnoreCase(s2)); // 0
1.3 字符串查找(超常用)
public static void main(String[] args) {
String s = "aaabbbcccaaabbbccc";
System.out.println(s.charAt(3)); // 'b'
System.out.println(s.indexOf('c')); // 6
System.out.println(s.indexOf("bbb")); // 3
System.out.println(s.lastIndexOf('c')); // 17
}
1.4 类型转换(开发必备)
1)数字 / 布尔 → 字符串
String s1 = String.valueOf(123);
String s2 = String.valueOf(12.34);
String s3 = String.valueOf(true);
2)字符串 → 数字
int a = Integer.parseInt("1234");
double d = Double.parseDouble("12.99");
3)大小写转换
String s = "Hello";
System.out.println(s.toUpperCase()); // HELLO
System.out.println(s.toLowerCase()); // hello
4)字符串 ↔ 字符数组
String s = "hello";
char[] ch = s.toCharArray(); // 转数组
String s2 = new String(ch); // 转回字符串
5)格式化字符串
String s = String.format("%d-%02d-%02d", 2025, 4, 2);
System.out.println(s); // 2025-04-02
1.5 字符串替换(创建新对象!)
String 替换不会改原串 ,只会返回新字符串。
String str = "helloworld";
System.out.println(str.replaceAll("l", "_")); // he__owor_d
System.out.println(str.replaceFirst("l", "_")); // he_loworld
1.6 字符串拆分(高频坑点)
普通拆分
String str = "hello world hello bit";
String[] arr = str.split(" ");
特殊字符必须转义
. * + | \ 都要加 \
String ip = "192.168.1.1";
String[] arr = ip.split("\\.");
1.7 字符串截取(左闭右开!)
String str = "helloworld";
System.out.println(str.substring(5)); // world
System.out.println(str.substring(0,5)); // hello
✅ 重点:包含开头,不包含结尾
1.8 trim ():去掉首尾空白
String str = " hello world ";
System.out.println(str.trim()); // hello world
2. String 不可变性(面试必考!)
2.1 什么是不可变?
String 对象一旦创建,内容永远不能改!所有 "修改" 操作(replace、trim、substring...)都会创建新字符串。
2.2 不可变的真正原因
- String 类被 final 修饰,不能被继承
- 底层 value 数组被 private final 修饰
- 没有对外提供任何修改数组的方法
❌ 错误:final 让数组内容不能改
✅ 正确:final 只让引用不能改;真正不可变是封装 + 不提供修改方法
2.3 为什么 String 要设计成不可变?
- 实现字符串常量池,节省内存
- 线程安全,不用加锁
- 哈希码稳定,适合做 HashMap key
- 更安全(密码、路径不能被篡改)
2.4 想频繁修改字符串用什么?
-
StringBuilder:单线程最快
-
StringBuffer:线程安全(慢)
StringBuilder sb = new StringBuilder();
sb.append("hello").append(" world");
3. 我给你额外补充的干货
🔥 高频题:
1. == 和 equals 的区别?
==:基本类型比值 ,引用类型比地址equals:默认比地址,String 重写后比内容
2. 下面代码创建几个对象?
String s = new String("abc");
答案:1 个或 2 个
常量池没有 "abc" → 创建 2 个
常量池已有 "abc" → 创建 1 个
3. String 为什么不可变?
类 + 数组 private + 无修改方法 + final 保障
4. 终极总结
- String 是引用类型,全类名 java.lang.String
- 比较内容用 equals (),别用 ==
- 常用方法:
charAtindexOfsplitsubstringtrimreplace
- String 不可变,所有修改都创建新对象
- 频繁修改用 StringBuilder