参考自–《Java技术核心卷1》
字符串
从概念上看,Java字符串就是Unicode字符序列。
Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义类,String.每个用双引号括起来的字符串都是String类的一个实例:
String e = ""; //空字符串
String s = "String";
1 子串
String类的substring方法可以从一个较大的字符串提取出一个子串:
String s = "Hello";
String sz = s.substring(0,3); //sz = "Hel"
创建了一个由字符"Hel"组成的字符串。
substring方法的第二个参数是不想复制的第一个位置。
上例中要复制的字符为0、1、2(从0~2,包括0和2)位置上的字符,直到3为止,但不包含3.
substring的工作方式有一个优点:容易计算子串的长度。字符串s.substring(a,b)的长度即为b-a.
2 拼接
Java允许使用+号连接(拼接)两个字符串。如:
String s1 = "Hello";
String s2 = " World";
String s = s1 + s2; //s的值为 "Hello World"
当将一个字符串与一个非字符串的值进行拼接时,后者被转换成字符串。
如果需要把多个字符串放到一起,用一个定界符分隔,可以使用静态join方法:
String all = String.join("/","S","M","L"); // all 等于 "S/M/L"(/可为其他符号)
3 不可变字符串
String类没有提供可用于修改字符串的方法,由于不能修改Java字符串中的字符,所以Java文档中将String类对象称为不可变字符串。
如果要修改字符串,只能“拆”“接”进行:如"Hello"修改成"Help"
String s1 = "Hello";
String s2 = s1.substring(0,3)+"p"; // s2 等于 "Help"
如同数字3永远是数字3一样,字符串"Hello"永远包含字符H,e,l,l,o的代码单元序列,而不能修改其中的任何一个字符。当然,可以修改字符串变量,让它引用另外一个新的字符串。
不可变字符串有一个优点:编译器可以让字符串共享。
为了弄清具体的工作方式,可以想象将各种字符串存放在公共的存储池中。字符串变量指向存储池中相应的位置。如果复制一个字符串变量 , 原始字符串与复制的字符串共享相同的字符。修改字符串变量即使它指向新的字符串。
由于Java具有垃圾回收机制,不存在内存遗漏问题。
4 检测字符串是否相等
可以使用equals方法检测两个字符串是否相等。对于表达式:
s.equals(t);
如果字符串s与字符串t相等,则返回true;否则,返回false。s与t可以是字符串变量,也可以是字符串常量。
要想检测两个字符串是否相等,而不区分大小写,可以使用equalsIgnoreCase方法:
"Hello".equalsIgnoreCase("hello"); //true
注:一定不要使用 == 运算符检测两个字符是否相等!
这个运算符只能够确定两个字符串是否放置在同一个位置上。当然,如果字符串放置在同一个位置上,它们必然相等。但是,完全有可能将内容相同的多个字符串的拷贝放置在不同的位置上。
如果虚拟机始终将相同的字符串共享,就可以使用运算符检测是否相等。但实际上只有字符串常量是共享的,而+或substring等操作产生的结果并不是共享的。因此,千万不要使用运算符测试字符串的相等性,以免在程序中出现糟糕的bug。从表面上看,这种bug很像随机产生的间歇性错误。
5 空串和Null串
空串""是长度为0的字符串。可以这样判断一个字符串是否为空:
if(str.length()==0)
或
if(str.equals(""))
空串是一个Java对象,有自己的串长度(0)和内容(空)。不过String变量还可以存放一个特殊的值,名为null,这表示目前没有任何对象与该变量关联。
要检查一个字符串是否为null,可以这样判断:
if(str == null)
有时需要检查一个字符串既不是null也不为空串:
if(str != null && str.length() != 0)
首先要检查str不为null(如果在一个null值上调用方法,会出现错误)。
6 码点与代码单元
Java字符串由char值序列组成。char数据类型是一个采用UTF-16编码表示的Unicode码点的代码单元。大多数的常用的Unicode字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。
length方法返回的即为采用UTF-16编码表示的给定字符串所需要的代码单元数量。
String s = "Hello";
int n = s.length(); // n 等于 5
要想得到实际的长度,即码点数量,可以调用:
int nCount = s.codePointCount(0,s.length());
调用s.charAt(n)将返回字符串位置n的代码单元,n介于0~s.length()-1之间。如:
char first = s.charAt(0); // first为s字符串的第一个字符,即'H'
要想得到第i个码点:
int index = s.offsetByCodePoints(0,i);
int cp = s.codePointAt(index);
注:如果要遍历一个字符串,并依次查看每一个码点,可使用codePoints方法,它会生成一个int值的“流”,每一个int值对应一个码点。可以把它转换为一个数组,再完成遍历:
int[] codePoints = s.codePoints().toArray();
反之,要把一个码点数组转换为一个字符串,可以使用构造函数:
String str = new String(codePoints,0,codePoints.length);
7 String API
Java中的String类包含了50多个方法。
- boolean startWith(String pre) 以 pre 开头
- boolean endWith(String end) 以 end 结尾
- int indexOf(String str) 返回与字符串str匹配的第一个子串的开始位置,如果不存在,返回-1
- int indexOf(String str,int fromIndex) 从fromIndex开始计算,返回与字符串str匹配的第一个子串的开始位置,如果不存在,返回-1
- int lastIndexOf(String str) 返回与字符串str匹配的最后一个子串的开始位置,这个位置从原始串尾开始计算;同样也可以有开始计算位置的参数fromIndex。
- String replace(CharSequence oldstring,CharSequence newstring) 返回一个新的字符串。这个字符串用newstring代替原始字符串中的所有oldstring.可以用String或StringBuilder对象作为参数
- String toLowerCase() 返回一个新的字符串(将原始字符串中的大写字母改为小写)
- String toUpperCase() 返回一个新的字符串(将原始字符串中的小写字母改为大写)
- String trim() 返回一个新的字符串。这个字符串删除了原始字符串头部和尾部的空格
在API注释中,有一些CharSequence类型的参数。这是一种接口类型,所有字符串都属于这个接口。CharSequence形参,完全可以传入String类型的实参。
8 构建字符串
有些时候,需要由较短的字符串构建字符串,而采用字符串连接的方式达到此目的的效率比较低。每次连接字符串,都会构建一个新的String对象,既耗时,又耗内存。
使用StringBuilder类可以避免这个问题的发生。
如果需要用许多小段的字符串构建字符串,那么应该按照下列步骤进行。
1.首先,构建一个空的字符串构建器:
StringBuilder builder = new StringBUilder();
2.当每次需要添加一部分内容时,就调用append方法:
builder.append(ch); //ch表示一个字符
builder.append(str); //str表示一个字符串
3.在需要构建字符串时调用toString方法,将可以得到一个String对象,其中包含了构建器中的字符序列:
String completedString = builder.toString();
注:在JDK5.0引入StringBuilder类。这个类的前身是StringBuffer,其效率稍有些低,但允许采用多线程的方式执行添加或删除字符的操作。如果所有字符串在一个单线程中编辑,则应该使用StringBuilder替代它。
以下是StringBuilder类中的重要方法:
- StringBuilder() 构建一个空的字符串构建器
- int length() 返回构建器或缓冲器中的代码单元数量
- StringBuilder append(String str) 追加一个字符串并返回this
- StringBuilder append(Char c) 追加一个代码单元并返回this
- void setCharAt(int i,Char c) 将第i个代码单元设置为c
- StringBuilder insert(int offset,String str) 在offset位置插入一个字符串并返回this
- StringBuilder insert(int offset,Char c) 在offset位置插入一个代码单元并返回this
- StringBuilder delete(int startIndex,int endIndex) 删除偏移量从startIndex到endIndex-1的代码单元并返回this
- String toString() 返回一个与构建器或缓冲器内容相同的字符串