# String
String 核心特性
String 是 java.lang 包下的核心类,用于表示字符串。Java 中所有双引号包裹的字符串字面量,本质都是 String 类的实例。
不可变性
String 是不可变字符序列,对象一旦创建,其内容无法修改。
– 底层:JDK 8 及之前用
private final char[] value存储字符;JDK 9 及之后改为byte[]节省空间
– 原因:数组被final修饰且私有,类不对外暴露修改数组的方法,所有 “修改” 操作都会返回新的 String 对象
– 优势:安全、可缓存复用、哈希值可缓存
字符串常量池
Java 为了节省内存、提升性能,设计了字符串常量池:
– 直接使用双引号赋值的字符串,会先检查常量池,存在则直接复用,不存在则创建后放入池中
–new String("abc")一定会在堆中创建新对象,同时也会检查常量池
–intern()方法:主动将字符串对象加入常量池并返回池中的引用
| 比较方式 | 基本数据类型 | 引用数据类型 |
|---|---|---|
== |
比较数值是否相等 | 比较内存地址是否相等(是否为同一个对象) |
equals() |
无(基本类型不能调用) | String 重写后比较字符串内容是否相等 |

String str1 = "abc";
String str2 = new String();
String str3 = "abc";
System.out.println(str1 == str2);//false
System.out.println(str1 == str3);//true
System.out.println(str2 == str3);//false
//全为true
System.out.println(str1.equals(str2));
System.out.println(str1.equals(str3));
System.out.println(str2.equals(str3));
String 常用方法:
| 方法 | 作用 |
|---|---|
int length() |
返回字符串长度 |
char charAt(int index) |
获取指定索引位置的字符 |
int indexOf(String str) |
查找子串第一次出现索引,找不到返回 -1 |
int indexOf(String str,int formIndex) |
查找str在formIndex之后出现的位置 是左闭区间 |
int lastIndexOf(String str) |
查找子串最后一次出现索引 |
String substring(int beginIndex) |
截取从 begin 到结尾的子串 |
String substring(int beginIndex, int endIndex) |
截取 [begin, end) |
boolean equals(Object obj) |
比较字符串内容是否相等(区分大小写) |
boolean equalsIgnoreCase(String another) |
比较内容,不区分大小写 |
boolean contains(CharSequence s) |
判断是否包含子串 |
boolean startsWith(String prefix) |
判断是否以 prefix 开头 |
boolean endsWith(String suffix) |
判断是否以 suffix 结尾 |
String toUpperCase() |
转大写 |
String toLowerCase() |
转小写 |
String trim() |
去除首尾空白字符 |
String strip() |
去除首尾空白字符(Java 11+,支持 Unicode 空白) |
String[] split(String regex) |
按正则表达式分割字符串 |
char[] toCharArray() |
转成字符数组 |
byte[] getBytes() |
转成字节数组 |
String replace(old, new) |
替换所有匹配的子串 |
String valueOf(Object obj) |
静态方法,把任意类型转成字符串 |
@Test
public void test2() {
String str = "java AndroidA";
System.out.println(str.length());//13
char[] chars = str.toCharArray();
char ch = str.charAt(5);//A
System.out.println(ch);
System.out.println(str.indexOf('A'));//5
System.out.println(str.indexOf('X'));//-1 找不到返回-1
System.out.println(str.indexOf('A', 6));//12
System.out.println(str.indexOf("And"));//5
System.out.println(str.lastIndexOf('A'));//12
}
@Test
public void test3() {
String str1 = "java";
String str2 = "Java";
System.out.println(str1.equals(str2));//false
System.out.println(str1.equalsIgnoreCase(str2));//true
String str = "java AndroidA";
System.out.println(str.contains("And"));//true
System.out.println(str.startsWith("java"));//true
//offset:偏移
System.out.println(str.startsWith("And", 5));//true
System.out.println(str.endsWith("oidA"));//true
System.out.println(str.isEmpty());//false
//"":空字符串,也是一个对象 ' '
System.out.println("".isEmpty());//true
char ch = ' ';
}
@Test
public void test44() {
// ""
//String str = "java And";
char[] array = {'j', 'a', 'v', 'a', ' ', 'A', 'n', 'd'};
String str = new String(array);
System.out.println(str);//java And
char[] chars = str.toCharArray();
System.out.println(chars);
//Arrays:操作数组的工具类
System.out.println(Arrays.toString(chars));
//[j, a, v, a, , A, n, d]
}
@Test
public void test424() {
String str = "java AndroidA";
String newStr = str.replace('A', 'B');
System.out.println(str);//java AndroidA
System.out.println(newStr);//java BndroidB
}
@Test
public void test66() {
String str = "java android python";
String[] array = str.split(" ");
System.out.println(Arrays.toString(array));
}
@Test
public void test87() {
// subtree: 子树
// substring:子字符串
String str = "java AndroidA";
System.out.println(str.substring(5));//AndroidA
//beginIndex – the beginning index, inclusive.
//endIndex – the ending index, exclusive.
System.out.println(str.substring(5, 8));//And
}
@Test
public void test181() {
String str = " java AndroidA ";
String newStr = str.trim();
System.out.println(str);// java AndroidA
System.out.println(newStr);//java AndroidA
}
@Test
public void test88() {
String str = "Java:Andorid:PHP:Python";
String[] array = str.split(":");
//System.out.println(array);
System.out.println(Arrays.toString(array));//[Java, Andorid, PHP, Python]
}
StringBuilder 与 StringBuffer
由于 String 不可变,频繁拼接字符串会创建很多临时对象,性能差,所以用 StringBuilder 或 StringBuffer,它们内容可变,适合频繁拼接。
| 类 | 可变 | 线程安全 | 性能 | 使用场景 |
|---|---|---|---|---|
| String | 不可变 | – | 慢,频繁拼接产生垃圾 | 内容不频繁改变 |
| StringBuilder | 可变 | 不安全 | 快 | 单线程,频繁拼接 |
| StringBuffer | 可变 | 安全,方法加 synchronized | 慢 | 多线程,频繁拼接 |
💡 推荐:大部分情况用 StringBuilder。
常用方法:
// 创建 StringBuilder
StringBuilder sb = new StringBuilder();
// 拼接 append,支持多种类型
sb.append("Hello");
sb.append(" World");
sb.append(123);
System.out.println(sb); // Hello World123
// insert 插入
sb.insert(5, ","); // 在索引 5 插入逗号
// delete 删除
sb.delete(0, 5); // 删除 [0,5)
// replace 替换
sb.replace(0, 5, "Hi");
// reverse 反转
sb.reverse();
// 转成 String
String result = sb.toString();
示例:高效拼接:
// 不好:每次拼接都创建新对象
String s = "";
for (int i = 0; i < 10000; i++) {
s = s + i; // 频繁创建新对象,性能差
}
// 好:用 StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i); // 在原有对象上修改,不创建新对象,性能好
}
String result = sb.toString();
@Test
public void test55() {
String str1 = "Java";
String str2 = "PHP";
String str3 = "Python";
String str4 = "UI";
String str = str1 + str2 + str3 + str4;//创建很多新对象,效率低
System.out.println(str);
StringBuffer buffer = new StringBuffer("C");
// buffer.append(str1);
// buffer.append(str2);
// buffer.append(str3);
// buffer.append(str4);
//链式编程
buffer.append(str1).append(str2).append(str3).append(str4);
System.out.println(buffer);
StringBuilder builder = new StringBuilder("C");
// builder.append(str1);
// builder.append(str2);
// builder.append(str3);
// builder.append(str4);
builder.append(str1).append(str2).append(str3).append(str4);
System.out.println(builder);
System.out.println("------------------");
//toString 不为打印,作用是转换为字符串
String str = builder.toString();
System.out.println(str);
}
包装数据类型
Java是纯面向对象语言,int、double都是基本数据类型。
包装数据类型是对基本数据类型的封装,为引用数据类型,默认值都为null
| 基本数据类型 | 包装类 |
|---|---|
byte |
Byte |
short |
Short |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
char |
Character |
boolean |
Boolean |
Java 5 之后提供自动装箱 / 拆箱机制,基本类型和包装类可以自动转换:
- 自动装箱:基本类型 → 包装类,底层调用
valueOf()方法 - 自动拆箱:包装类 → 基本类型,底层调用
xxxValue()方法
@Test
public void test45() {
//public static final int MAX_VALUE = 0x7fffffff;
System.out.println(Integer.MAX_VALUE);
//自动装箱和自动拆箱
Integer integer1 = Integer.valueOf(4);
System.out.println(integer1);//4
Integer integer2 = 4;//自动装箱
System.out.println(integer2);//4
//int i = integer2.intValue();
int num1 = integer2;//自动拆箱
System.out.println(num1);//4
Integer integer = 3;
int num2 = integer + 4;
integer = integer + 5;
}
包装类的核心用途:类型转换
包装类最常用的场景是:基本数据类型与字符串之间的相互转换。
(1)基本类型 → 字符串
// 方式1:拼接空字符串
String str1 = 123 + "";
// 方式2:包装类 toString() 方法
String str2 = Integer.toString(3);
String str3 = Double.toString(3.14);
// 方式3:String.valueOf() 静态方法
String str4 = String.valueOf(100);
(2)字符串 → 基本类型
// 方式1:parseXxx() 静态方法(最常用)
int num1 = Integer.parseInt("23");
double num2 = Double.parseDouble("3.14");
boolean flag = Boolean.parseBoolean("true");
// 方式2:valueOf() 先转包装类,再自动拆箱
int num3 = Integer.valueOf("4");
String 与数组的互转
// 1. String → char 数组
String str = "hello";
char[] chars = str.toCharArray();
// 2. char 数组 → String
// 方式1:构造方法
String s1 = new String(chars);
// 方式2:valueOf 静态方法
String s2 = String.valueOf(chars);