一、String 类
String 类是 Java 中用于表示字符串的核心类,其底层实现为不可变字符序列(一旦创建,内容无法修改)。
字符串创建
Java 提供了 4 种常见的字符串创建方式,具体实现如下:
public class StringBuild {
public static void main(String[] args) {
// 1.直接创建(推荐,会复用字符串常量池中的对象)
String str1 = "abc";
System.out.println(str1);
// 2.新建对象创建(会创建两个对象:常量池中的"abc" + 堆中的String对象)
String str2 = new String("abc");
System.out.println(str2);
// 3.通过字符数组创建
char[] crr = new char[]{'a', 'b', 'c'};
String str3 = new String(crr);
System.out.println(str3);
// 4.通过字节数组创建(字节对应 ASCII 码,97='a'、98='b'、99='c')
byte[] brr = new byte[]{97 ,98 ,99};
String str4 = new String(brr);
System.out.println(str4);
}
}
字符串查找
提供多种查找方法,支持查找单个字符或子字符串,支持正向/反向查找。
public class StringFind {
public static void main(String[] args) {
String str = "hello meat ooo";
// 1. 查找指定索引的字符
System.out.println(str.charAt(4));
System.out.println("============================================================");
// 2. 正向查找(从前往后)
// 2.1 查找第一次出现指定字符的下标
System.out.println(str.indexOf('o'));
// 2.2 从指定索引开始,查找第一次出现指定字符的下标
System.out.println(str.indexOf('a', 6));
// 2.3 查找第一次出现指定字符串的第一个字符的下标
System.out.println(str.indexOf("ooo"));
// 2.4 从指定索引开始,查找第一次出现指定字符串的第一个字符的下标
System.out.println(str.indexOf("ooo", 10));
System.out.println("============================================================");
// 3. 反向查找(从后往前)
// 3.1 从后往前找第一次出现指定字符的下标
System.out.println(str.lastIndexOf('t'));
// 3.2 从指定索引开始,从后往前找第一次出现指定字符的下标
System.out.println(str.lastIndexOf('t', 10));
// 3.3 从后往前找第一次出现指定字符串的下标
System.out.println(str.lastIndexOf("ooo"));
// 3.4 从指定索引开始,从后往前找第一次出现指定字符串的下标
System.out.println(str.lastIndexOf("ooo", 10));
}
}
字符串比较
字符串比较分为引用地址比较和内容比较,两种方式的用途不同。
public class StringMethod {
public static void main(String[] args) {
String str1 = new String("Hello");
String str2 = new String("Hello");
String str3 = new String("World");
String str4 = str1;
// 1. 比较引用地址(判断是否为同一个对象):==
System.out.println(str1 == str2); // false(不同对象,堆地址不同)
System.out.println(str1 == str4); // true(同一对象,引用地址相同)
System.out.println("============================================================");
// 2. 比较字符串内容(返回布尔类型):str1.equals(str2)
System.out.println(str1.equals(str2)); // true(内容相同)
System.out.println(str1.equals(str4)); // true(内容相同)
System.out.println("============================================================");
// 3. 比较内容(按字典序,返回整型):str1.compareTo(str2)
// 返回 0:内容相同;返回正数:str1 > str2;返回负数:str1 < str2
System.out.println(str1.compareTo(str2)); // 0
System.out.println(str1.compareTo(str3)); // 负数(H < W)
System.out.println("============================================================");
// 4. 比较内容(忽略大小写,按字典序返回整型):str1.compareToIgnoreCase(str2)
System.out.println(str1.compareToIgnoreCase(str2)); // 0
System.out.println(str1.compareToIgnoreCase(str3)); // 负数
System.out.println("============================================================");
}
}
字符串替换
支持替换全部匹配内容或仅替换第一个匹配内容。
public class StringReplace {
public static void main(String[] args) {
String str = "Hello meat";
// 1. 替换全部匹配的字符/字符串:str.replaceAll()
System.out.println(str.replaceAll("l", "p"));
// 2. 替换首个匹配的字符/字符串:str.replaceFirst()
System.out.println(str.replaceFirst("l", "p"));
}
}
字符串拆分
将字符串按指定分隔符拆分为字符串数组,支持限制拆分次数,特殊分隔符需要转义。
public class StringSpilt {
public static void main(String[] args) {
String str = "Hello World Hello meat";
// 1. 将字符串全部以空格拆分,用字符串数组接收结果
String[] srr1 = str.split(" ");
for (String s : srr1) {
System.out.println(s);
}
System.out.println("============================================================");
// 2. 将字符串以空格拆分,最多拆分 2 次(得到 2 个元素的数组)
String[] srr2 = str.split(" ", 2);
for (String s : srr2) {
System.out.println(s);
}
System.out.println("============================================================");
// 3. 特殊分隔符(. | * + , 等)需要使用 \\ 转义才能正常拆分
String str2 = "name=ZhangSan&age=18";
String[] srr3 = str2.split("=|&");
for (String s : srr3) {
System.out.println(s);
}
}
}
字符串截取和去除空格
字符串截取
按指定索引范围截取子字符串,遵循「左闭右开」原则。
去除空格
仅去除字符串两端的空格,中间空格保留。
public class SubStringAndTrim {
public static void main(String[] args) {
String str1 = "hello meat";
// 1. 字符串截取
// 1.1 从指定索引截取到字符串结尾:str.substring(index)
System.out.println(str1.substring(5));
// 1.2 截取指定索引范围内的内容(左闭右开):str.substring(beginIndex, endIndex)
System.out.println(str1.substring(5, 8));
System.out.println("============================================================");
String str2 = " hello world ";
// 2. 去除两边的空格:str.trim()
System.out.println("原始字符串:" + str2);
System.out.println("去除两端空格后:" + str2.trim());
}
}
intern() 方法
intern() 方法用于将堆中的 String 对象入池(字符串常量池),复用常量池中的对象,减少内存占用。
public class StringIntern {
public static void main(String[] args) {
char[] ch = new char[]{'a', 'b', 'c'};
String str1 = new String(ch);
// 调用此方法后,将 str1 对象的内容放入字符串常量池中(若不存在)
str1.intern();
// "abc" 已存在于字符串常量池中,str2 直接引用常量池中的对象
String str2 = "abc";
// 返回 true,若未调用 intern() 方法则返回 false
System.out.println(str1 == str2);
}
}
字符串转换
支持多种数据类型与字符串之间的相互转换,以及字符串的大小写、格式转换。
public class StringTransfer {
public static void main(String[] args) {
// 1. 其他数据类型转换为字符串:String.valueOf(...)(推荐,避免空指针异常)
String s1 = String.valueOf(1); // 整型 -> 字符串
String s2 = String.valueOf(1.1); // 浮点型 -> 字符串
String s3 = String.valueOf(true); // 布尔型 -> 字符串
String s4 = String.valueOf(new Student("LiHua", 18)); // 自定义对象 -> 字符串(依赖 toString() 方法)
System.out.println(s1 + " " + s2 + " " + s3 + " " + s4);
System.out.println("============================================================");
// 2. 字符串转为基本数据类型:封装类.parseXxx("...")
int a = Integer.parseInt("1"); // 字符串 -> 整型
double b = Double.parseDouble("1.1"); // 字符串 -> 浮点型
System.out.println(a);
System.out.println(b);
System.out.println("============================================================");
// 3. 字符串大小写转换
String str1 = "Hello";
String str2 = "HELLO";
System.out.println(str1.toUpperCase()); // 小写 -> 大写
System.out.println(str2.toLowerCase()); // 大写 -> 小写
System.out.println("============================================================");
// 4. 字符串 <-> 字符数组
// 4.1 字符串转为字符数组:str.toCharArray()
String str3 = "Hello";
char[] ch = str3.toCharArray();
for (char c : ch) {
System.out.print(c + " ");
}
System.out.println();
System.out.println("============================================================");
// 4.2 字符数组转为字符串:new String(字符数组)
String str4 = new String(ch);
System.out.println(str4);
System.out.println("============================================================");
// 5. 字符串格式化输出:String.format("格式字符串", 参数...)
String str5 = String.format("%d,%d,%d", 2020,1,1);
System.out.println(str5);
}
}
重写 toString() 方法
自定义对象转换为字符串时,默认调用 Object 类的 toString() 方法(返回「类名@哈希值」),重写后可返回自定义格式的内容。
class Student {
String name;
int age;
// 构造方法
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 重写 toString() 方法
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
二、StringBuffer 和 StringBuilder
由于 String 是不可变字符序列,频繁修改字符串会产生大量临时对象,浪费内存。StringBuffer 和 StringBuilder 是可变字符序列,专门用于频繁修改字符串的场景,两者的方法基本一致,核心区别在于线程安全性。
核心区别
StringBuffer:线程安全,方法添加了synchronized关键字修饰,多线程环境下安全,效率较低。StringBuilder:非线程安全,无synchronized修饰,单线程环境下效率更高(推荐优先使用)。
重要说明
StringBuffer、StringBuilder不能与String直接转换。String转StringBuffer/StringBuilder:调用构造方法或append()方法。StringBuffer/StringBuilder转String:调用toString()方法。- 两者的核心方法(如
append())声明有区别(StringBuffer多了synchronized)。
// StringBuilder 的 append() 方法(无同步锁)
public static StringBuilder append(String s) {
StringBuilder sb = new StringBuilder();
sb.append(s);
return sb;
}
// StringBuffer 的 append() 方法(有同步锁 synchronized)
public static synchronized StringBuffer append(String s) {
StringBuffer sb = new StringBuffer();
sb.append(s);
return sb;
}
StringBuilder 常用方法
StringBuffer 的方法使用方式与 StringBuilder 完全一致,此处以 StringBuilder 为例演示核心方法。
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = sb1;
sb1.append(" "); // 字符串尾插内容
sb1.append("meat");
System.out.println(sb1 == sb2); // true(可变对象,修改的是自身内容,引用地址不变)
System.out.println(sb1.charAt(0)); // 获取指定下标的字符
System.out.println(sb1.length()); // 获取字符串实际长度
System.out.println(sb1.capacity()); // 获取底层数组的容量(大于等于实际长度)
sb1.setCharAt(0, 'H'); // 修改指定下标的字符为'H'
sb1.insert(0, "Wow"); // 在下标为0的位置插入字符串
System.out.println(sb1.indexOf("hello")); // 正向查找第一次出现指定字符串的下标
System.out.println(sb1.lastIndexOf("hello")); // 反向查找第一次出现指定字符串的下标
sb1.deleteCharAt(0); // 删除指定下标的字符
sb1.delete(0, 2); // 删除[0, 2)范围内的字符(左闭右开)
String str1 = sb1.substring(0, 2); // 截取[0, 2)范围内的字符,返回新的String对象
String str2 = sb1.toString(); // 将StringBuilder转换为String对象
sb1.reverse(); // 翻转字符串内容
}