字符串
创建字符串
字符串在 Java 编程中被广泛使用,它们是字符序列。在 Java 编程语言中,字符串是对象。
Java 平台提供了 String
类来创建和操作字符串。
创建字符串最直接的方法是编写
String greeting = "Hello world!";
在这种情况下,"Hello world!" 是一个字符串字面量 - 代码中的一系列字符,用双引号括起来。每当在代码中遇到字符串字面量时,编译器都会创建一个 String
对象,其值为 - 在这种情况下,Hello world!。
与任何其他对象一样,您可以使用 new
关键字和构造函数来创建 String
对象。该 String
类有 13 个构造函数,允许您使用不同的来源(例如字符数组)提供字符串的初始值
char[] helloArray = { 'h', 'e', 'l', 'l', 'o', '.' };
String helloString = new String(helloArray);
System.out.println(helloString);
此代码段的最后一行显示 hello
。
注意: 该
String
类是不可变的,因此一旦创建,String
对象就无法更改。该String
类包含许多方法,其中一些将在下面讨论,这些方法似乎修改了字符串。由于字符串是不可变的,因此这些方法实际上所做的是创建并返回一个包含操作结果的新字符串。
字符串长度
用于获取有关对象信息的方法称为访问器方法。您可以与字符串一起使用的一种访问器方法是 length()
方法,该方法返回字符串对象中包含的字符数。在执行以下两行代码后,len
等于 17
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
回文是一个对称的单词或句子 - 它正着和倒着拼写相同,忽略大小写和标点符号。这是一个简短且效率低下的程序,用于反转回文字符串。它调用了 String
方法 charAt(i)
,该方法返回字符串中第 ith 个字符,从 0 开始计数。
public class StringDemo {
public static void main(String[] args) {
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
char[] tempCharArray = new char[len];
char[] charArray = new char[len];
// put original string in an
// array of chars
for (int i = 0; i < len; i++) {
tempCharArray[i] =
palindrome.charAt(i);
}
// reverse array of chars
for (int j = 0; j < len; j++) {
charArray[j] =
tempCharArray[len - 1 - j];
}
String reversePalindrome =
new String(charArray);
System.out.println(reversePalindrome);
}
}
运行程序会产生以下输出
doT saw I was toD
为了完成字符串反转,程序必须将字符串转换为字符数组(第一个 for
循环),将数组反转到第二个数组(第二个 for
循环),然后转换回字符串。该 String
类包含一个方法,getChars()
,用于将字符串或字符串的一部分转换为字符数组,因此我们可以用以下内容替换上述程序中的第一个 for 循环
palindrome.getChars(0, len, tempCharArray, 0);
连接字符串
该 String
类包含一个用于连接两个字符串的方法
string1.concat(string2);
这将返回一个新的字符串,即 string1
,并在其末尾添加 string2
。
您也可以使用 concat()
方法与字符串字面量一起使用,如
"My name is ".concat("Rumplestiltskin");
字符串通常使用 +
运算符连接,如
"Hello," + " world" + "!"
这将导致
"Hello, world!"
+
运算符在打印语句中被广泛使用。例如
String string1 = "saw I was ";
System.out.println("Dot " + string1 + "Tod");
这将打印
Dot saw I was Tod
这种连接可以是任何对象的混合。对于每个不是 String
的对象,都会调用其 toString()
方法将其转换为 String
。
注意: 直到 Java SE 15,Java 编程语言不允许字符串字面量跨越源文件中的行,因此您必须在多行字符串的每一行末尾使用
+
连接运算符。例如
String quote =
"Now is the time for all good " +
"men to come to the aid of their country.";
使用 +
连接运算符在行之间断开字符串,再次在 print
语句中非常常见。
从 Java SE 15 开始,您可以编写二维字符串字面量
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
创建格式字符串
您已经看到了 printf()
和 format()
方法的使用,以打印格式化的数字输出。该 String
类有一个等效的类方法,format()
,它返回一个 String
对象而不是 PrintStream
对象。
使用 String
的静态 format()
方法允许您创建一个可以重复使用的格式化字符串,而不是一次性打印语句。例如,而不是
System.out.printf("The value of the float " +
"variable is %f, while " +
"the value of the " +
"integer variable is %d, " +
"and the string is %s",
floatVar, intVar, stringVar);
您可以编写
String fs;
fs = String.format("The value of the float " +
"variable is %f, while " +
"the value of the " +
"integer variable is %d, " +
" and the string is %s",
floatVar, intVar, stringVar);
System.out.println(fs);
将字符串转换为数字
通常,程序最终会在字符串对象中获得数字数据 - 例如,用户输入的值。
该 Number
子类包装原始数字类型 (Byte
、Integer
、Double
、Float
、Long
和 Short
)都提供了一个名为 valueOf()
的类方法,该方法将字符串转换为该类型的对象。以下是一个示例,ValueOfDemo
,它从命令行获取两个字符串,将它们转换为数字,并对这些值执行算术运算
public class ValueOfDemo {
public static void main(String[] args) {
// this program requires two
// arguments on the command line
if (args.length == 2) {
// convert strings to numbers
float a = (Float.valueOf(args[0])).floatValue();
float b = (Float.valueOf(args[1])).floatValue();
// do some arithmetic
System.out.println("a + b = " +
(a + b));
System.out.println("a - b = " +
(a - b));
System.out.println("a * b = " +
(a * b));
System.out.println("a / b = " +
(a / b));
System.out.println("a % b = " +
(a % b));
} else {
System.out.println("This program " +
"requires two command-line arguments.");
}
}
}
以下是当您使用 4.5
和 87.2
作为命令行参数时程序的输出
a + b = 91.7
a - b = -82.7
a * b = 392.4
a / b = 0.0516055
a % b = 4.5
注意: 每个
Number
子类包装原始数字类型也提供了一个parseXXXX()
方法。例如,parseFloat()
可用于将字符串转换为原始数字。由于返回的是原始类型而不是对象,因此parseFloat()
方法比valueOf()
方法更直接。例如,在ValueOfDemo
程序中,我们可以使用
float a = Float.parseFloat(args[0]);
float b = Float.parseFloat(args[1]);
将数字转换为字符串
有时您需要将数字转换为字符串,因为您需要以字符串形式对其值进行操作。有几种简单的方法可以将数字转换为字符串
int i;
// Concatenate "i" with an empty string; conversion is handled for you.
String s1 = "" + i;
或
// The valueOf class method.
String s2 = String.valueOf(i);
每个 Number
子类都包含一个类方法,toString()
,它将将其原始类型转换为字符串。例如
int i;
double d;
String s3 = Integer.toString(i);
String s4 = Double.toString(d);
ToStringDemo
示例使用 toString()
方法将数字转换为字符串。程序然后使用一些字符串方法来计算小数点前后数字的个数。
public class ToStringDemo {
public static void main(String[] args) {
double d = 858.48;
String s = Double.toString(d);
int dot = s.indexOf('.');
System.out.println(dot + " digits " +
"before decimal point.");
System.out.println( (s.length() - dot - 1) +
" digits after decimal point.");
}
}
该程序的输出是
3 digits before decimal point.
2 digits after decimal point.
通过索引获取字符和子字符串
String 类包含许多用于检查字符串内容、查找字符串中的字符或子字符串、更改大小写以及其他任务的方法。
可以通过调用 charAt()
访问器方法来获取字符串中特定索引处的字符。第一个字符的索引为 0,而最后一个字符的索引为 length() - 1
。例如,以下代码获取字符串中索引为 9 的字符
String anotherPalindrome = "Niagara. O roar again!";
char aChar = anotherPalindrome.charAt(9);
索引从 0 开始,因此索引为 9 的字符为 'O',如下图所示
如果要从字符串中获取多个连续字符,可以使用 substring 方法。substring 方法有两个版本
String substring(int beginIndex, int endIndex)
:返回一个新的字符串,它是此字符串的子字符串。子字符串从指定的beginIndex
开始,扩展到索引为endIndex - 1
的字符。String substring(int beginIndex)
:返回一个新的字符串,它是此字符串的子字符串。整数参数指定第一个字符的索引。这里,返回的子字符串扩展到原始字符串的末尾。
以下代码从尼亚加拉回文获取从索引 11 扩展到但不包括索引 15 的子字符串,即单词“roar”
String anotherPalindrome = "Niagara. O roar again!";
String roar = anotherPalindrome.substring(11, 15);
用于操作字符串的其他方法
以下是一些其他用于操作字符串的 String
方法
String[] split(String regex)
和String[] split(String regex, int limit)
:根据字符串参数(包含正则表达式)指定的匹配项搜索并相应地将此字符串拆分为字符串数组。可选的整数参数指定返回数组的最大大小。正则表达式在标题为 正则表达式 的部分中介绍。CharSequence subSequence(int beginIndex, int endIndex)
:返回一个新的字符序列,该序列从beginIndex
索引构造到endIndex - 1
。String trim()
:返回此字符串的副本,其中已删除前导和尾随空格。String toLowerCase()
和String toUpperCase()
:返回此字符串的副本,转换为小写或大写。如果不需要进行任何转换,这些方法将返回原始字符串。
在字符串中搜索字符和子字符串
以下是一些其他用于在字符串中查找字符或子字符串的 String
方法。String
类提供访问器方法,这些方法返回字符串中特定字符或子字符串的位置:indexOf()
和 lastIndexOf()
。indexOf()
方法从字符串的开头向前搜索,而 lastIndexOf()
方法从字符串的末尾向后搜索。如果找不到字符或子字符串,indexOf()
和 lastIndexOf()
将返回 -1。
String
类还提供了一个搜索方法 contains,如果字符串包含特定字符序列,则返回 true
。当您只需要知道字符串是否包含字符序列,而确切位置并不重要时,请使用此方法。
搜索方法如下
int indexOf(int ch)
和int lastIndexOf(int ch)
:返回指定字符的第一个(最后一个)出现的索引。int indexOf(int ch, int fromIndex)
和int lastIndexOf(int ch, int fromIndex)
:返回指定字符的第一个(最后一个)出现的索引,从指定的索引向前(向后)搜索。int indexOf(String str)
和int lastIndexOf(String str)
:返回指定子字符串的第一个(最后一个)出现的索引。int indexOf(String str, int fromIndex)
和int lastIndexOf(String str, int fromIndex)
:返回指定子字符串的第一个(最后一个)出现的索引,从指定的索引向前(向后)搜索。boolean contains(CharSequence s)
:如果字符串包含指定的字符序列,则返回true
。
注意:
CharSequence
是一个接口,由String
类实现。因此,您可以使用字符串作为contains()
方法的参数。
将字符和子字符串替换到字符串中
String
类几乎没有用于将字符或子字符串插入字符串的方法。通常,它们是不需要的:您可以通过将从字符串中删除的子字符串与要插入的子字符串连接起来来创建一个新字符串。
但是,String
类确实有四种用于替换找到的字符或子字符串的方法。它们是
String replace(char oldChar, char newChar)
:返回一个新的字符串,该字符串是通过将此字符串中所有出现的oldChar
替换为newChar
而得到的。String replace(CharSequence target, CharSequence replacement)
:将此字符串中与文字目标序列匹配的每个子字符串替换为指定的文字替换序列。String replaceAll(String regex, String replacement)
:将此字符串中与给定正则表达式匹配的每个子字符串替换为给定的替换。String replaceFirst(String regex, String replacement)
:将此字符串中与给定正则表达式匹配的第一个子字符串替换为给定的替换。
正则表达式在标题为 正则表达式 的课程中讨论。
String 类在实践中
以下类 Filename
演示了如何使用 lastIndexOf()
和 substring()
来隔离文件名中的不同部分。
注意:以下
Filename
类中的方法不进行任何错误检查,并假设其参数包含完整的目录路径和带有扩展名的文件名。如果这些方法是生产代码,它们将验证其参数是否正确构造。
public class Filename {
private String fullPath;
private char pathSeparator,
extensionSeparator;
public Filename(String str, char sep, char ext) {
fullPath = str;
pathSeparator = sep;
extensionSeparator = ext;
}
public String extension() {
int dot = fullPath.lastIndexOf(extensionSeparator);
return fullPath.substring(dot + 1);
}
// gets filename without extension
public String filename() {
int dot = fullPath.lastIndexOf(extensionSeparator);
int sep = fullPath.lastIndexOf(pathSeparator);
return fullPath.substring(sep + 1, dot);
}
public String path() {
int sep = fullPath.lastIndexOf(pathSeparator);
return fullPath.substring(0, sep);
}
}
这是一个程序 FilenameDemo
,它构造一个 Filename
对象并调用其所有方法
public class FilenameDemo {
public static void main(String[] args) {
final String FPATH = "/home/user/index.html";
Filename myHomePage = new Filename(FPATH, '/', '.');
System.out.println("Extension = " + myHomePage.extension());
System.out.println("Filename = " + myHomePage.filename());
System.out.println("Path = " + myHomePage.path());
}
}
以下是程序的输出
Extension = html
Filename = index
Path = /home/user
如下图所示,我们的扩展方法使用 lastIndexOf()
来定位文件名中最后一个句点 (.
) 的出现位置。然后,substring 使用 lastIndexOf()
的返回值来提取文件名扩展名,即从句点到字符串末尾的子字符串。此代码假设文件名中包含句点;如果文件名不包含句点,lastIndexOf()
返回 -1,并且 substring 方法抛出 StringIndexOutOfBoundsException
。
此外,请注意扩展方法使用 dot + 1
作为 substring()
的参数。如果句点字符 (.
) 是字符串的最后一个字符,则 dot + 1
等于字符串的长度,这比字符串中最大的索引大 1(因为索引从 0 开始)。这是一个合法的 substring()
参数,因为该方法接受等于但不大于字符串长度的索引,并将其解释为“字符串的末尾”。
比较字符串和字符串的部分
String
类有许多方法用于比较字符串和字符串的部分。下表列出了这些方法。
boolean endsWith(String suffix)
和boolean startsWith(String prefix)
:如果此字符串以或以作为方法参数指定的子字符串开头,则返回true
。boolean startsWith(String prefix, int offset)
:考虑从索引offset
开始的字符串,如果它以作为参数指定的子字符串开头,则返回true
。int compareTo(String anotherString)
:按字典顺序比较两个字符串。返回一个整数,指示此字符串是否大于(结果为 > 0)、等于(结果为 = 0)或小于(结果为 < 0)参数。int compareToIgnoreCase(String str)
:按字典顺序比较两个字符串,忽略大小写差异。返回一个整数,指示此字符串是否大于(结果为 > 0)、等于(结果为 = 0)或小于(结果为 < 0)参数。boolean equals(Object anObject)
:当且仅当参数是表示与该对象相同字符序列的String
对象时,返回true
。boolean equalsIgnoreCase(String anotherString)
:当且仅当参数是表示与该对象相同字符序列的String
对象时,返回true
,忽略大小写差异。boolean regionMatches(int toffset, String other, int ooffset, int len)
:测试此字符串的指定区域是否与String
参数的指定区域匹配。区域的长度为len
,并从此字符串的索引toffset
和另一个字符串的ooffset
开始。boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
:测试此字符串的指定区域是否与String
参数的指定区域匹配。区域的长度为len
,并从此字符串的索引toffset
和另一个字符串的ooffset
开始。布尔参数指示是否应忽略大小写;如果为true
,则在比较字符时忽略大小写。boolean matches(String regex)
:测试此字符串是否与指定的正则表达式匹配。正则表达式在名为 正则表达式 的课程中讨论。
以下程序 RegionMatchesDemo
使用 regionMatches()
方法在另一个字符串中搜索字符串
public class RegionMatchesDemo {
public static void main(String[] args) {
String searchMe = "Green Eggs and Ham";
String findMe = "Eggs";
int searchMeLength = searchMe.length();
int findMeLength = findMe.length();
boolean foundIt = false;
for (int i = 0;
i <= (searchMeLength - findMeLength);
i++) {
if (searchMe.regionMatches(i, findMe, 0, findMeLength)) {
foundIt = true;
System.out.println(searchMe.substring(i, i + findMeLength));
break;
}
}
if (!foundIt)
System.out.println("No match found.");
}
}
此程序的输出为 Eggs
。
该程序一次遍历 searchMe()
所引用的字符串中的一个字符。对于每个字符,该程序调用 regionMatches()
方法来确定从当前字符开始的子字符串是否与程序正在查找的字符串匹配。
上次更新: 2021 年 9 月 14 日