字符串是Java程序中经常处理的对象,如果字符串运用得不好,将影响到程序运行的效率。在Java中,字符串作为String类的实例来处理。以对象的方式处理字符串,将字符串更加灵活、方便。了解字符串上可用的操作,可以节省程序编写与维护的时间。本章从创建字符串开始向读者讲解字符串本身的特性以及字符串上可用的重要操作等。
本章的知识价格及重难点如下。表示重点内容,⭐表示难点内容
单个字符可以用char类型保存,多个字符组成的文本就需要保存在String对象中。String通常被称为字符串,一个String对象最多可以保存(2³²–1)个字节(占用4GB空间大小)的文本内容。
在Java语言中,字符串必须包含在一对双引号("")之内。例如:
"23.23"、"ABCDE"、"你好"
以上这些都是字符串常量,字符串常量可以是系统能够显示的任何文字信息,甚至可以是单个字符。
误区警示
在Java中由双引号("")包围的都是字符串,不能作为其他数据类型来使用,如"1+2"的输出结果不可能是3。
可以通过以下语法格式来声明字符串变量:
String str;
String:指定该变量为字符串类型
str:任意有效的标识符,表示字符串变量的名称。
声明字符串变量s,代码如下:
String s;
说明:声明的字符串变量必须经过初始化才能使用,否则编译器会报出“变量未被初始化错误”。
在Java语言中,将字符串作为对象来处理,因此可以像创建其他类对象一样来创建字符串对象。创建对象要使用类的构造方法。String类的常用构造方法如下。
(1)String(char a[])
该方法用一个字符数组a创建String对象,代码如下:
char a[] = {'g','o','o','d'};
String s = new String(a);
等价于 ||
\_/
String s = new String("good")
(2)String(char a[],int offset,int length)
该方法提取字符数组a中的一部分创建一个字符串对象。参数offset表示开始截取字符串的位置,length表示截取字符串的长度。代码如下:
char a[] = {'s','t','u','d','e','n','t'};
String s = new String(a,2,4);
等价于 ||
\_/
String s = new string("uden");
(3)String(char[] value)
该构造方法可分配一个新的String对象,使其表示字符数组参数中所有元素连接的结果。代码如下:
char a[] = {'s','t','u','d','e','n','t'};
String s = new String(a);
等价于 ||
\_/
String s = new String("Student");
除通过以上几种使用String类的构造方法来创建字符串变量外,还可通过将字符串常量的引用赋值给一个字符串变量来创建字符串。代码如下:
String str,str2;
str1 = "We are students"
str2 = "We are students"
此时,str1与str2引用相同的字符串常量,因此具有相同的实体,内存示意图如下图:
对于已声明的字符串,可以对其进行相应的操作,连接字符串就是字符操作中较简单的一种。可以对多个字符串进行连接,也可使字符串与其他数据类型进行连接。
使用“+”运算符可实现连接多个字符串的功能。“+”运算符可以连接多个String对象并产生一个新的Stiring对象。
例题1:先连接一副对联的上、下联,再分行输出在控制台上
在项目中创建Join类,在主方法中创建两个String型变量,它们的值分别使“春色绿千里”和“马蹄香万家”,使用“+”运算符连接这两个String型变量和“\n”,在控制台上输出连接后的字符串。实例代码和结果如下图:
字符串也可同其他基本数据类型进行连接。如果字符串同其他数据类型进行连接,会将其他数据类型的数据直接转换成字符串。
例题2:统计每天的阅读和上机时间
在项目中创建Link类,在主方法中创建数值型变量,实现将字符串与整型、浮点型变量相连接的结果输出。实例代码和运行结果如下:
本实例实现的是将字符串常量与整型变量booktime和浮点型变量practice相连后的结果输出。在这里booktime和practice都不是字符串,当它们与字符串相连接时会自动调用toString()方法并转换成字符串形式,然后参与字符串连接。
误区警示:
只要“+”运算符的一个操作是字符串,编译器就会将另一个操作数转换成字符串形式,所以应谨慎地将其他数据类型的数据与字符串相连,以免出现意想不到的结果。
如果将上面例题2中的输出语句修改为:
System.out.println("我每天花费"+booktime+"小时看书";+(practice+booktime)+"小时上机练习");
则输出结果如下图:
为什么会这样呢?这是由于运算符是有优先级的,圆括号的优先级最高,所以先被执行,然后再将结果与字符串相连接。
字符串作为对象,可通过相应方法获取字符串的有效信息,如获取某字符串的长度、某个索引位置的字符等。
使用String类的length()方法可获取声明的字符串对象的长度。语法如下:
str.length();
其中,str为字符串对象。
获取字符串长度,代码如下:
String str = "We are students";
int size = str.length();
上段代码是将字符串str的长度赋值给int型变量size,此时变量size的值为15,这表示length()方法返回的字符串的长度(包括字符串中的空格)。
String类提供了两种查找字符串的方法,即indexOf()与lastIndexOf()方法。这两种方法都允许在字符串中搜索指定条件的字符或字符串。indexOf()方法返回的是搜索的字符或字符串首次出现的位置,lastIndexOf()方法返回的是搜索的字符或字符串最后一次出现的位置。
(1)indexOf(String s)
该方法用于返回参数字符串s在指定字符串中首次出现的索引位置。当调用String类的indexOf()方法时,会从当前字符串的位置开始搜索s的位置。如果没有检索到字符串s,该方法的返回值是-1。语法如下:
str.indexOf(substr)
str:任意字符串对象。
substr:要搜索的字符串。
查找字符a在字符串str中的索引位置,代码如下:
String str = "We are students";
int size = str.indexOf("a");//变量size的值是3
理解字符串的索引位置,要对字符串的下标有所了解。在Java语言中,String对象是用数组表示的。字符串的下标是0~length()-1。因此,字符串“We are students”的下标如下表所示。
字符串str的下标 | ||||||||||||||||
——→ | W | e | a | r | e | s | t | u | d | e | n | t | s | |||
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | ||
↑字母a的索引位置 |
(2)lastindexOf(String str)
该方法用于返回指定字符串最后一次出现的索引位置。当调用String类的lastIndexOf()方法时,会从当前字符串的开始位置检查参数字符串str,并将最后一次出现str的索引位置返回。如果没有检索到字符串str,该方法返回-1。语法如下:
str.lastIndexOf(substr)
str:任意字符串对象。
substr:要搜索的字符串。
说明lastIndexOf()方法中的参数是空字符串""(注意没有空格),则返回的结果与调用length()方法的返回结果相同。
例题:用两种方式判断字符串的长度
在项目中创建Text类,在主方法中创建String对象,先使用lastIndexOf()方法查看字符串str中空字符串的位置,再输出这个字符串的长度,查看这两个结果是否相同。实例代码和允许结果如下图:
使用charAt()方法可将指定索引处的字符返回。语法如下:
str.charAt(index)
str:任意字符串。
index:整型值,用于指定要返回字符的下标。
例题:查看指定索引位置上的字符
在项目中创建Ref类,在主方法中创建String对象,使用charAt()方法查看字符串,str中索引位置是6的字符。实例代码和结果如下:
课堂笔记:
String类中包含了很多操作方法,允许程序员对字符串进行操作来满足实际编程中的需要。本节将讲解几种常见的字符串操作。
通过String类的substring()方法可对字符串进行截取。substring()方法被两种不同的重载形式,来满足不同的需要。这些形式的共同点就是都利用字符串的下标进行截取,且应明确字符串下标是从0开始的。
(1)substring(int beginIndex)
该方法返回的是从指定的索引位置开始截取直到该字符串结尾的子串。语法如下:
str.substring(int beginIndex)
其中,beginIndex指定从某一索引处开始截取字符串.
截取字符串,代码如下:
String str = "Hello World";//定义字符串str
String substr = str.substring(3);//获取字符串,此时substr值为lo World
使用substring(beginIndex)截取字符串的过程如下表所示:
字符串str的下标 | ||||||||||||
——→ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ||
H | e | l | l | o | W | o | r | l | d | |||
↑____________________________________↑ | str.substring(3) |
||||||||||||
误区警示:在字符串中,空格占用一个索引位置。
(2)substring(int beginIndex,int endIndex)
该方法返回的是从字符串某一索引位置开始截取至某一索引位置的结束的子串。语法如下:
substring(int beginIndex,int endIndex)
beginIndex:开始截取子字符串的索引位置。
endInex:子字符串在整个字符串中的结束位置。
例题:《将进酒》的作者是哪位诗人?
在项目中创建Subs类,在主方法中创建String对象,实现使用substring()方法对字符串进行截取,并将截取后形成的新串输出。实例代码如下图:
trim()方法返回字符串的副本,忽略前导空格和尾部空格。语法如下:
str.trim()
其中,str为任意字符串对象。
例题:去掉字符串首、尾的空格
在项目中创建Blak类,在主方法中创建String对象,在控制台上输出字符串原来的长度和去掉首、尾空格后的长度。实例代码和结果如下图:
replace()方法可实现将指定的字符或字符串替换成新的字符或字符串。语法如下:
str.replace(CharSequence target,CharSequence replacement)
target:要替换的字符或字符串。
replacement:用于替换原来字符串的内容。
replace()方法返回的结果是一个新的字符串。如果字符串或字符串oldChar没有出现在该对象表达式中的字符串序列中,则将原字符串返回。
例题:将单词中的字母a替换为字母A
在项目中创建NewStr类,在主方法中创建String型变量,将该变量中的字母a替换换成A,并将替换后的字符串输出。实例代码和结果如下图:
说明:如果要替换的字符oldChar在字符串中重复出现多次,replace()方法会将所有oldChar全部替换成newChar。例如:
String str = "java project";
String newstr = str.replace("j","J");
此时,newstr的值为Java proJect。
需要注意的是,要替换的字符oldChar的大小写要与原字符串的大小写保持一致,否则不能成功替换。例如,上面的实例如果写成如下语句,则不能成功替换:
String str = "java project";
String new = str.replace("P","t");
startsWith()方法与endsWith()方法分别用于判断字符串是否以指定的内容开始或结束。这两个方法的返回值都为Boolean类型。
(1)startsWith()方法
该方法用于判断当前字符串对象的前缀是否为参数指定的字符串。语法如下:
str.startsWith(String prefix)
其中,prefix是指作为前缀的字符串。
(2)endsWith()方法
该方法用于判断当前字符串是否为以给定的子字符串结束。语法如下:
str.endsWith(String suffix)
其中,suffix是指作为后缀的字符串。
例题:判断字符串是否以指定的内容开始或结束
在项目中创建StartOrEnd类,在主方法中创建两个String型变量,它们的值分别为“22045612”和“21304578”,先判断“22045612”是否是以“22”开始的,再判断“21304578”是否是以“78”结尾的。实例代码和结果如下图:
对字符串对象进行比较不能简单地使用比较运算符“==”,因为比较运算符比较的是两个字符串的地址是否相同。即使两个字符串的内容相同,两个对象的内存地址也是不同的,使用比较运算符仍然会返回false。使用比较运算符比较两个字符串,代码如下:
String tom = new String("I am a student");
String jerry = new String("I am a student");
boolean b = (tom == jerry);
此时,布尔型变量b的值为false,因为字符串是对象,tom、jerry是引用,内存示意图如下图所示。
因此,要比较两个字符串的内容是否相等,应使用equals()方法和equalsIgnoreCase()方法。
(1)equals()方法
如果两个字符串具有相同的字符和长度,则使用equals()方法进行比较时,返回true。否则,返回false。语法如下:
str.equals(String otherstr)
其中,str、otherstr是要比较的两个字符串对象。
(2)equalsIgnoreCase()方法
使用equals()方法对字符串进行比较时是区分大小写的,而使用equalsIgnoreCase()方法是在忽略了大小写的情况下比较两个字符串是否相等,返回结果仍为boolean类型。语法如下:
str.equalsIgnoreCase(String otherstr)
其中,str、otherstr是要比较的两个字符串对象。
通过下面的例子可以看出equals()方法和equalsIgnoreCase()方法的区别。
例题:判断“abc”与“ABC”是否相等
在项目中创建Opinion类,在主方法中创建两个String型变量,它们的值分别为“abc”和“ABC”,判断这两个字符串是否相等。实例代码和运行结果如下图:
compareTo()方法为按字典顺序比较两个字符串,该比较基于字符串中各个字符的Unicode值,按字典顺序将String对象表示的字符序列与参数字符串所表示的字符序列进行比较。如果按字典顺序此String对象位于参数字符串之前,则比较结果为一个负整数;如果按子典顺序此String对象位于之后,则比较结果为一个正整数;如果这两个字符串相等,则结果为0。语法如下:
str.compare To(String otherstr)
其中,str、otherstr是要比较的两个字符串对象。
说明:compareTo()方法只有在equals(Object)方法返回true时才返回0。
例题:判断字母b的位置
在项目中创建Wordbook类,在主方法中创建3个String变量,它们的值分别为a、b和c,使用compare To()方法判断字母b的位置,即在字母a的后面,在字母c的前面。实例代码和结果如下:
String类的toLowerCase()方法可将字符串中的所有大写字母改写为小写字母,而toUpperCase()方法可将字符串中的所有小写字母改成大写字母。
(1)toLowerCase()方法
该方法将字符串中的所有大写字母转换为小写字母。如果字符串中没有应该被转换的字符,则将原字符串返回;否则将返回一个新的字符串,将原字符串中每个大写字母都转换成小写,字符串长度不变。语法如下:
str.toLowerCase()
其中,str是要进行转换的字符串
(2)toUpperCase()方法
该方法将字符串中的所有小写字母转换为大写字母。如果字符串中没有应该被转换的字符,则将原字符串返回;否则将返回一个新的字符串,将原字符串中每个小写字母都转换成大写,字符串长度不变。语法如下:
str.toUpperCase()
其中,str是要进行转换的字符串
说明:使用toLowerCase方法和toUpperCase()方法进行大小写转换时,数字或其他非英文字母类字符不受影响。
例题:字母大小写转换
在项目中创建UpAndLower类,在主方法中创建一个值为“Oh My God”的String型变量,对这个字符串进行字母大小写转换,将转换后的结果输出在控制台上。实例代码和结果如下图:
使用split()方法可以使字符串按指定的分割字符或字符串进行分割,并将分割后的结果存放在字符串数组中。split()方法提供了以下两种字符串分割形式。
(1)split(String sign)
该方法可根据给定的分割符对字符串进行拆分。语法如下:
str.split(String sign)
其中,sign为分割字符串的分割符,也可以使用正则表达式。
说明:没有统一的对字符进行分割的符号。如果想定义多个分割符,可使用符合“|”。例如“|=”表示分割符为“,”和“=”。
(2)split(String sign,int limit)
该方法可根据给定的分割符对字符串进行拆分,并限定拆分的次数。语法如下:
str.split(String sign,int limit)
sign:分割字符串的分割符,也可以使用正则表达式。
limit:限制的分割次数。
例题:按要求分割“192.168.0.1”
在项目中创建Division类,在主方法中创建一个值为“192.168.0.1”的String型变量,先按照“.”分割字符串,再按照“.”对这个字符串进行两次分割。实例代码和结果如下图:
课堂笔记:
运行结果:
String类的静态format()方法用于创建格式化的字符串。format()方法有两种重载形式。
(1)format(String format,Object...agrs)
该方法使用指定的格式字符串和参数返回一个格式化字符串,格式化后的新字符串使用本地默认的语言环境。语法如下:
str.format(String format,Object...agrs)
format:格式字符串
agrs:格式字符串中由格式说明符引用的参数。如果还有格式说明符以外的参数,则忽略这些额外的参数。此参数的数目是可变的,可以为0。
(2)format(Local l,String format Object...args)
该方法使用指定的语言环境、格式字符串和参数返回一个格式化字符串,格式化后的新字符串使用其指定的语言环境。语法如下:
format(Local l,String format Object...args)
l:格式化过程中要应用的语言环境。如果1为null,则不进行本地化。
format:格式字符串。
agrs:格式字符串中由格式说明符引用的参数。如果还有格式说明符以外的参数,则忽略这些额外的参数。此参数的数目是可变的,可为0。
在应用程序设计中,经常需要显示日期和时间。如果想输出满意的日期和时间格式,一般要编写大量的代码、经过各种算法才能实现。format()方法通过给定的特殊转换符作为参数来实现对日期和时间的格式化。
(1)日期格式化
返回一个月中的天数,代码如下:
Date date = new Date();//创建Date对象date
String s = String.format("%te",date);//创建format()方法date进行格式化
上述代码中变量s的值是当前日期中的天数,如今天是15号,则s的值为15;%te是转换符。常用的日期格式化转换如下图所示:
例题:按照格式输出今天的年、月、日。
在项目中创建Eval类,控制台输出今天的年、月、日。其中,输出格式为4位年份、月份全称和2位日期。实例代码和结果如下:
(2)时间格式化
使用format()方法不仅可以完成日期的格式化,也可以实现时间的格式化。时间的格式化转换要比日期的格式化转换符更多、更精确,它可以将时间格式化为时、分、秒、毫秒等。格式化时间的转换符如下图所示。
例题:按照格式输出当下的时、分、秒
在项目中创建GetDate类,按照格式输出当下的时、分、秒。其中时、分、秒以2位24时制小时数、2位分钟数、2位秒数的格式进行输出。实例代码和运行结果如下:
(3)格式化常见的日期时间组合
格式化日期与时间组合的转换符定义了各种日期时间组合的格式,其中最常用的如下图所示:
例题:按照格式输出当下的年、月、日
在项目中创建DateAndTime类,在控制台上输出当前日期的全部信息后,按照“2008-03-25”格式输出当下的年、月、日。实例代码如下图:
常规类型格式化可应用于任何参数类型,可通过下图所示的转换符来实现。
例题:使用转换符获取表达式的结果
在项目中创建General类,选择并使用恰当的转换符分别输出400/2、3》5和用十六进制整数显示200的结果。实例代码如下:
课堂笔记:
正则表达式通常被用于判断语句中,用来检查某一字符串是否满足某一格式。正则表达式是含有一些具有特殊意义字符的字符串,这些特殊字符称为正则表达式的元字符。例如,“\\d”表示数字0~9中的任何一个,“\\d”就是元字符。正则表达式中的元字符及其意义如下表所示:
元字符 | 正则表达式中的写法 | 意义 |
. | . | 任何一个字符 |
\d | \\d | 0~9的任何一个数字 |
\D | \\D | 任何一个非数字字符 |
\s | \\s | 空白字符,如'\t'、'\n' |
\S | \\S | 非空白字符 |
\w | \\w | 可用于标识符的字符,但不包括“$” |
\W | \W | 不可用于标识符的字符 |
\p{Lower} | \\p{Lower} | 小写字母a~z |
\p{Upper} | \\p{Upper} | 大写字母A~Z |
\p{ASCII} | \\P{ASCII} | ASCII字符 |
\p{Alpha} | \\p{Alpha} | 字母字符 |
\p{Digit} | \\p{Dight} | 十进制数字,即0~9 |
\p{Alnum} | \\p{Alnum} | 数字或字母字符 |
\p{Punct} | \\p{Punct} | 标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_'{|}~ |
\p{Graph} | \\p{Graph} | 可见字符:[\p{Alnum}\p{Punct}] |
\p{Print} | \\p{Print} | 可打印字符:[\p{Graph}\x20] |
\p{Blank} | \\p{Blank} | 空格或制表符:[\t] |
\p{Cntrl} | \\p{Cntrl} | 控制字符:[\x00-\x1F\x7F] |
说明:在正则表达式中,“.”代表任何一个字符,因此在正则表达式中如果想使用普通意义的点字符“.”,必须使用转义字符“\”。
在正则表达式中,可以使用方括号括起若干个字符来表示一个元字符,该元字符可代表方括号中的任何一个字符。例如,reg = "[abc]4",这样字符串a4、b4、c4、都是和正则表达式匹配的字符串。方括号元字符还可以为其他格式。如:
[^456]:代表4、5、6之外的任何字符。
[a-r]:代表a~r中的任何一个字母。
[a-zA-Z]:可表示任意一个英文字母。
[a-e[g-z]]:代表a~e或g~z中的任何一个字母(并运算)。
[a-o&&[def]]:代表字母d、e、f(交运算)。
[a-d&&[^bc]]:代表字母a、d(差运算)。
在正则表达式中允许使用限定修饰符来限定元字符出现的次数。例如,“A*”代表A可以在字符串中出现0次或多次。限定修饰符的用法如下表所示。
限定修饰符 | 意义 | 示例 | 限定修饰符 | 意义 | 示例 |
? | 0次或1次 | A? | {n} | 正好出现n次 | A{2} |
* | 0次或多次 | A* | {n,} | 至少出现n次 | A{3,} |
+ | 一次或多次 | A+ | {n,m} | 出现n~m次 | A{2,6} |
例题:验证E-mail地址是否“合法”
在项目中创建Judge类,使用正则表达式来判断“aaa@”“aaaaa”“[email protected]”这3个E-mail地址哪一个是合法的。实例代码和结果如下:
正则表达式分析:
通常情况下E-mail的格式为“[email protected]”。字符X表示任意的一个或多个字符,@为E-mail地址中的特有符号,符号@后还有一个或多个字符,之后是字符“.com”,也可能后面还有类似“.cn”标记。总结E-mail地址的这些特点,可以书写正则表达式“\\w+@\\w+(\\.\\w{2,3})*\\.\\w{2,3}”来匹配E-mail地址。字符集“\\w”匹配任意字符,符号“+”表示字符可以出现1次或多次,表达式“(\\.\\w{2,3})*”表示形如“.com”格式的字符串可以出现0次或多次。而最后的表达式“\\.\\w{2,3}”用于匹配E-mail地址中的结尾字符,如“.cn”。
课堂笔记:
创建成功的字符串对象,其长度是固定的,内容不能被改变和编译。虽然使用“+”可以达到附加新字符或字符串的目的,但“+”会产生一个新的String实例,会在内存中创建新的字符串对象。如果重复的对字符串中进行修改,将极大地增加系统开销。而JDK新增了可变的字符序列StringBuilder类,大大提高了频繁增加字符串的效率。
例题:效率比拼
在项目中创建Jerque类,先使用“+”运算符把0~9999逐一拼接成字符串,再把0~9999逐一追加到StringBuilder类的对象中,在控制台上分别输出这两种方式的消耗时间。实例代码和结果如下:
通过这一实例可以看出,两种操作执行的时间差距很大如果在程序中频繁地附加字符串,建议使用StringBuilder类新创建的StringBuilder 对象初始容量是16个字符,可以自行指定初始长度。如果附加的字符超过可容纳的长度,则StringBuilder 对象将自动增加长度以容纳被附加的字符。若要使用StringBuilder类最后输出字符串结果,可使用toString()方法。利用StringBuilder类中的方法可动态执行添加、删除和插入等字符串的编辑操作。该类的常用方法如下。
(1)1.append()方法
该方法用于向字符串生成器中追加内容。通过该方法的多个重载形式,可实现接受任何类型的数据,如int、boolean、char、String、double 或者另一个字符串生成器等。语法如下:
append(content)
其中,content 表示要追加到字符串生成器中的内容,可以是任何类型的数据或者其他对象。
(2)insert(int offset, arg)方法
该方法用于向字符串生成器中的指定位置插入数据内容。通过该方法的不同重载形式,可实现向字符串生成器中插入int、float、char和boolean等基本数据类型的数据或其他对象。语法如下:
insert(int offset arg)
offset: 字符串生成器的位置。该参数必须大于等于 0,且小于等于此序列的长度。
arg: 将插入至字符串生成器的位置。该参数可以是任何数据类型的数据或其他对象向字符串生成器中指定的位置添加字符,代码如下:
StringBuilder bf = new StringBuilder("hello");//创建字符生成器
bf.insert(5,"world");//添加至字符生成器的位置及内容
System.out.println(bf.toString());//此时输出信息为helloworld
(3)3.delete(int start , int end)方法
移除此序列的子字符串中的字符。该子字符串从指定的 start 处开始,一直到索引end-1处的字符如果不存在这种字符,则一直到序列尾部。如果start等于end,则不发生任何更改。语法如下:
delete(int start,int end)
start:将要删除的字符串的起点位置
end:将要删除的字符串的终点位置
删除指定位置的子字符串,代码如下:
StringBuilder bf = new StringBuilder("StringBuilder");//创建字符串生成器
bf.delete(5,10);//删除的子字符串
System.out.println(bf.toString());//此时输出的信息为Stringder
说明:想要了解更多StringBuilder类的方法,可查询java.lang.StringBuilder的API说明。