系列中的上一篇
当前教程
字符串
系列中的下一篇

系列中的上一篇: 字符

系列中的下一篇: 字符串构建器

字符串

 

创建字符串

字符串在 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 子类包装原始数字类型 (ByteIntegerDoubleFloatLongShort)都提供了一个名为 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.587.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',如下图所示

Char indexes in a string

字符串中的字符索引

如果要从字符串中获取多个连续字符,可以使用 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); 

Extracting characters from a string with substring

使用 substring 从字符串中提取字符

 

用于操作字符串的其他方法

以下是一些其他用于操作字符串的 String 方法

 

在字符串中搜索字符和子字符串

以下是一些其他用于在字符串中查找字符或子字符串的 String 方法。String 类提供访问器方法,这些方法返回字符串中特定字符或子字符串的位置:indexOf()lastIndexOf()indexOf() 方法从字符串的开头向前搜索,而 lastIndexOf() 方法从字符串的末尾向后搜索。如果找不到字符或子字符串,indexOf()lastIndexOf() 将返回 -1。

String 类还提供了一个搜索方法 contains,如果字符串包含特定字符序列,则返回 true。当您只需要知道字符串是否包含字符序列,而确切位置并不重要时,请使用此方法。

搜索方法如下

注意:CharSequence 是一个接口,由 String 类实现。因此,您可以使用字符串作为 contains() 方法的参数。

 

将字符和子字符串替换到字符串中

String 类几乎没有用于将字符或子字符串插入字符串的方法。通常,它们是不需要的:您可以通过将从字符串中删除的子字符串与要插入的子字符串连接起来来创建一个新字符串。

但是,String 类确实有四种用于替换找到的字符或子字符串的方法。它们是

正则表达式在标题为 正则表达式 的课程中讨论。

 

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 类有许多方法用于比较字符串和字符串的部分。下表列出了这些方法。

以下程序 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 日


系列中的上一篇
当前教程
字符串
系列中的下一篇

系列中的上一篇: 字符

系列中的下一篇: 字符串构建器