模式切换
字符串
在 Java 中,字符串是一个非常重要的数据类型,用于存储文本信息。Java 提供丰富的字符串操作功能,主要通过 String
类、StringBuilder
类和 StringBuffer
类来实现。
String 类
String
类是 Java 中最常用的字符串类,它是不可变的(immutable),即一旦创建就不能被修改。所有字符串操作都会返回一个新的字符串对象。
声明字符串
在 Java 中可以通过以下方式声明字符串:
java
String str1 = "Hello, World!";
String str2 = new String("Hello, World!");
str1
是通过字面量生命的,即一个字符串常量,存储在字符串常量池中。str2
是通过new
关键字创建的,会在堆内存中创建一个新的字符串对象。
注意:
- 在 Java 中,由双引号("")包围的都是字符串,不能作为其他数据类型来使用。如"1+2"的输出不可能是 3。
- 声明字符串变量必须经过初始化才能使用,否则编译器会报出“可能尚未初始化变量”的错误。
创建字符串
Java 中将字符串作为对象来管理,因此可以像创建其他类对象一样来创建字符串对象。创建对象要使用类的构造方法,String
类提供了多种构造方法来创建字符串。
- String(char a[])
用字符数组 a 创建 String 对象。
java
char[] charArray = {'H', 'e', 'l', 'l', 'o'};
String str3 = new String(charArray); // 结果为 "Hello"
- String(char a[], int offset, int length)
提取字符数组 a 中从 offset 开始的 length 个字符创建 String 对象。
java
char[] charArray = {'H', 'e', 'l', 'l', 'o'};
String str4 = new String(charArray, 1, 3); // 结果为 "ell"
- String(char[] value)
用字符数组 value 创建 String 对象。该构造方法可以分配一个新的 String 对象,使其表示字符数组参数中所有元素连接的结果。
java
char[] charArray = {'H', 'e', 'l', 'l', 'o'};
String str5 = new String(charArray); // 结果为 "Hello"
除了上述几种使用 String 类的构造方法来创建字符串变量外,还可以通过字符串常量的引用赋值给一个字符串变量。
java
String str6, str7;
str6 = "Hello"; // 字符串常量赋值
str7 = "Hello"; // 字符串常量赋值
图 内存示意图,str6 与 str 7 引用相同的字符串常量
连接字符串
连接多个字符串
可以使用 +
运算符或 concat()
方法来连接字符串:
java
String str5 = "Hello";
String str6 = "World";
String str7 = str5 + " " + str6; // 使用 + 运算符连接字符串
String str8 = str5.concat(" ").concat(str6); // 使用 concat() 方法连接字符串
Java 中一句相连的字符串不能分行书写,需要使用 +
运算符连接,如下:
java
String str = "Hello, "
+ "World!";
连接其他数据类型
+
运算符不仅可以连接字符串,还可以连接其他数据类型(如整数、浮点数等),Java 会自动将其转换为字符串:
java
int num = 123;
String str9 = "The number is " + num; // 结果为 "The number is 123"
获取字符串信息
获取字符串长度
使用 length()
方法可以获取字符串的长度:
java
String str10 = "Hello World";
int length = str10.length(); // 长度为 11
字符串查找
可以使用 indexOf()
和 lastIndexOf()
方法来查找子字符串或字符的位置。
indexOf()
方法返回子字符串或字符第一次出现的位置。lastIndexOf()
方法返回子字符串或字符最后一次出现的位置,如果未找到则返回 -1。
java
String str11 = "Hello, World!";
int index1 = str11.indexOf('o'); // 返回第一个 'o' 的位置,结果为 4
int index2 = str11.lastIndexOf('o'); // 返回最后一个 'o' 的位置,结果为 8
int index3 = str11.indexOf("World"); // 返回子字符串 "World" 的起始位置,结果为 7
理解字符串的索引位置,需要对下标(索引)概念有所了解。在 Java 中,字符串的索引位置从 0 开始,即第一个字符的索引位置为 0,第二个字符的索引位置为 1,以此类推。
图 字母 o 的索引位置
获取指定索引位置的字符
使用 charAt()
方法可以获取指定索引位置的字符:
java
String str12 = "Hello";
char ch = str12.charAt(1); // 返回索引为 1 的字符,结果为 'e'
字符串操作
获取子字符串
使用 substring()
方法可以截取字符串,该方法被两种不同的方法重载:
- substring(int beginIndex):从指定索引开始截取到末尾。
- substring(int beginIndex, int endIndex):从指定索引开始截取到指定索引(不包括)。
java
String str13 = "Hello, World!";
String subStr1 = str13.substring(7); // 从索引 7 开始到末尾,结果为 "World!"
String subStr2 = str13.substring(7, 12); // 从索引 7 开始到索引 12(不包括),结果为 "World"
图 str13.substring(7) 的截取过程
去除空格
使用 trim()
方法可以去除字符串两端的空格:
java
String str14 = " Hello, World! ";
String trimmedStr = str14.trim(); // 结果为 "Hello, World!"
字符串替换
使用 replace()
方法可以替换字符串中的字符或子字符串:
- replace(char oldChar, char newChar):将字符串中的 oldChar 替换为 newChar。如果字符串中有多个 oldChar,则全部替换。区分大小写。
java
String str15 = "Hello, World!";
String replacedStr1 = str15.replace('o', 'a'); // 结果为 "Hella, Warld!"
String replacedStr2 = str15.replace("World", "Java"); // 结果为 "Hello, Java!"
判断字符串的开始和结束
使用 startsWith()
和 endsWith()
方法可以判断字符串是否以指定的前缀或后缀开始或结束:
java
String str16 = "Hello, World!";
boolean startsWithHello = str16.startsWith("Hello"); // 结果为 true
boolean endsWithWorld = str16.endsWith("World!"); // 结果为 true
判断字符串是否相等
比较字符串是否相等时,不能使用 ==
运算符,因为 ==
运算符比较的是两个字符串对象的引用地址。应该使用 equals()
方法或 equalsIgnoreCase()
方法来判断两个字符串的内容是否相等。
使用 equals()
方法可以判断两个字符串的内容是否相等,equalsIgnoreCase()
方法则忽略大小写:
java
String str17 = "Hello";
String str18 = "hello";
boolean isEqual1 = str17.equals(str18); // 结果为 false
boolean isEqual2 = str17.equalsIgnoreCase(str18); // 结果为 true
按字典顺序比较两个字符串
使用 compareTo()
方法可以按字典顺序比较两个字符串,该比较基于字符串中各个字符的 Unicode 值,按字典顺序将此 String 对象表示的字符序列与参数字符串所表示的字符序列进行比较。如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为负数;如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为正数;如果两个字符串相等,则比较结果为 0。
java
String str19 = "apple";
String str20 = "banana";
int result = str19.compareTo(str20); // 结果为负数,因为 "apple" 在 "banana" 之前
字母大小写转换
使用 toLowerCase()
和 toUpperCase()
方法可以转换字符串的大小写。在转换时,数字或非字母字符不会被改变。
java
String str21 = "Hello, World!";
String lowerCaseStr = str21.toLowerCase(); // 结果为 "hello, world!"
String upperCaseStr = str21.toUpperCase(); // 结果为 "HELLO, WORLD!"
字符串分割
使用 split()
方法可以根据指定的字符或字符串分割字符串,分割后的结果存储在字符串数组中。
- split(String sign):根据指定的字符或字符串分割字符串。其中,sign 可以使用正则表达式。如果想定义多个分隔符,可以使用
|
连接。 - split(String sign, int limit):根据指定的字符或字符串分割字符串,最多分割 limit 次。
java
String str22 = "apple,banana,orange";
String[] fruits1 = str22.split(","); // 结果为 ["apple", "banana", "orange"]
String[] fruits2 = str22.split(",", 2); // 结果为 ["apple", "banana,orange"]
格式化字符串
String 类的静态方法 format()
可以用来格式化字符串。format()
方法有两种重载形式:
- format(String format, Object... args):根据指定的格式字符串和参数返回一个格式化字符串。
- format(Locale l, String format, Object... args):根据指定的区域设置、格式字符串和参数返回一个格式化字符串。
- l:区域设置,用于格式化日期、时间等。
- format:格式字符串,包含格式化转换符。
- args:参数列表,用于替换格式字符串中的格式化转换符。
日期和时间字符串格式化
在程序设计中经常要现实日期和时间。在 Java 中,format()
方法通过给定特殊的转换符作为参数来实现对日期和时间的格式化。
日期格式化
表 常用的日期格式化转换符
示例:
java
import java.util.Date;
public class Main {
public static void main(String[] args) {
Date date = new Date();
String year = String.format("%tY", date); // 年份,结果为 "2023"
String month = String.format("%tm", date); // 月份,结果为 "10"
String day = String.format("%td", date); // 日期,结果为 "05"
}
}
时间格式化
表 时间格式化转换符
示例:
java
import java.util.Date;
public class Main {
public static void main(String[] args) {
Date date = new Date();
String hour = String.format("%tH", date); // 24 小时制,结果为 "15"
String minute = String.format("%tM", date); // 分钟,结果为 "08"
String second = String.format("%tS", date); // 秒,结果为 "12"
}
}
日期和时间的组合格式
表 常见的日期和时间的组合格式
示例:
java
import java.util.Date;
public class Main {
public static void main(String[] args) {
Date date = new Date();
String time = String.format("%tc", date); // 完整的日期和时间,结果为 "星期四 十月 05 15:08:12 CST 2023"
String form = String.format("%tF", date); // 年-月-日,结果为 "2023-10-05"
}
}
常规类型格式化
常规类型的格式化可以应用于任何参数类型,通过下表所示的转换符来实现:
表 常规转换符
示例:
java
String str1 = String.format("%d", 400 / 2); // 整数,结果为 "200"
String str2 = String.format("%b", 3 > 2); // 布尔值,结果为 "true"
String str3 = String.format("%x", 200); // 十六进制,结果为 "c8"
使用正则表达式
正则表达式通常被用于判断语句中,用来检查某一字符串是否满足某一个是。正则表达式是含有一些具有特殊含义的字符串,这些特殊的字符串称为正则表达式的元字符。
正则表达式中元字符及其含义如下表所示:
表 正则表达式中的元字符
在正则表达式中可以使用中括号([]
)来表示一个字符集合,其中的字符可以是单个字符,也可以是一个范围。例如,[abc]1
表示字符 a1、b1 或 c1,[a-z]
表示从 a 到 z 的任意字符。 中括号还可以为其他格式,如:
[^abc]
:表示除了 a、b、c 之外的任意字符。[a-r]
:表示从 a 到 r 的任意字符。[a-zA-Z]
:表示从 a 到 z 或从 A 到 Z 的任意字符,这里即表示所有的英文字母。[a-e[m-p]]
:表示 a 到 e 或 m 到 p 中的任意一个字符,这里即表示进行并集操作。[a-z&&[def]]
:表示 a 到 z 且为 d、e、f 中的任意一个字符,这里即表示进行交集操作。[a-z&&[^bc]]
:表示 a 到 z 且不为 b、c 中的任意一个字符,这里即表示进行差集操作。
在正则表达式中允许使用限定修饰符来限定元字符出现的次数。例如:A*
表示 A 出现 0 次或多次,A+
表示 A 出现 1 次或多次,A?
表示 A 出现 0 次或 1 次,A{n}
表示 A 出现 n 次,A{n,}
表示 A 出现 n 次或多次,A{n,m}
表示 A 出现 n 到 m 次。
限定修饰符的用法如下表所示:
表 限定修饰符
在 Java 中,可以使用 matches()
方法来判断字符串是否匹配某个正则表达式:
java
String str = "Hello, World!";
boolean isMatch = str.matches("Hello.*"); // 结果为 true
字符串生成器
由于 String
类是不可变的,创建成功的字符串对象其长度是固定的,内容不能被改变和编译。虽然使用 +
运算符和 concat()
方法可以连接字符串,但这会产生一个新的 String 实例,频繁的字符串操作会产生大量临时对象,影响性能。为此,Java 提供了 StringBuilder
和 StringBuffer
类,它们是可变的字符串类。
StringBuilder
StringBuilder 是非线程安全的,适用于单线程环境下的字符串操作:
- append(content):追加字符串,等价于
+
运算符。javaStringBuilder sb = new StringBuilder(); sb.append("Hello"); sb.append(", "); sb.append("World!"); String result = sb.toString(); // 结果为 "Hello, World!"
- insert(int offset, arg):在指定位置插入字符串。java
StringBuilder sb = new StringBuilder("Hello World!"); sb.insert(5, ", "); // 在索引 5 处插入 ", " String result = sb.toString(); // 结果为 "Hello, World!"
- delete(int start, int end):删除指定位置的字符串。java
StringBuilder sb = new StringBuilder("Hello, World!"); sb.delete(5, 7); // 删除索引 5 到 7 的字符 String result = sb.toString(); // 结果为 "Hello World!"
StringBuffer
StringBuffer 是线程安全的,适用于多线程环境下的字符串操作:
java
StringBuffer sb = new StringBuffer();
sb.append("Hello");
sb.append(", ");
sb.append("World!");
String result = sb.toString(); // 结果为 "Hello, World!"