
2.3 字符串
字符串是由字符组成的序列,用双引号括起来的一个字符序列构成了字符串,如“this is a string”。字符串不是Java语言中的基本数据类型,而是对象类型(String类的实例)。
可以用很多方式来定义一个字符串,例如:
String aStr1="This is a string"; String aStr2=new String("This is a string"); String aStr3=""; //空字符串 String aStr4=null; //空值
前面已经提到,一个对象类型的变量中存储的值是所指向对象的地址。所以上面的对象变量aStr1中的值是一个地址,该地址指向内存中的一个字符串对象“This is a string”。
例如:
String aStr="abc"; // ① aStr指向内存中的一个字符串对象"abc" aStr="xyz"; // ② aStr指向内存中重新生成的一个对象"xyz"
注意:null是一个特殊的空值,可以赋值给任何对象类型的变量。上面的例子中aStr3和aStr4是不同的,aStr3指向内存中的一个字符串对象(但是该字符串对象中没有任何字符);aStr4由于是一个空值,所以不指向任何字符串对象。
字符串被创建后,其中的内容不能再改变。如果要改变字符串的内容,需要重新生成新的字符串对象。
如图2.4所示,执行完语句①时,aStr指向内存中的一个字符串对象“abc”;执行语句②时,在内存中先生成一个字符串对象“xyz”,然后aStr再指向该对象。

图2.4 改变字符串的内容
可以使用打印语句将字符串的内容打印出来,例如:
String aStr="abc"; System.out.println(aStr);
2.3.1 字符串连接
Java语言中,使用操作符“+”可以把两个字符串连接起来形成新的字符串。例如:
String aStr="abc"+"xyz"; // aStr="abcxyz" String aStr="abc"+" "+"xyz"; // aStr="abc xyz"
还可以用“+”把字符串和其他类型的值(包括基本数据类型和对象类型)连接起来,其他类型的值首先被转换为字符串,然后再进行字符串之间的连接运算。
字符串和基本数据类型的值连接:
String aStr="value="+20; // aStr="value=20" String aStr="value="+true; // aStr="value=true"
字符串和对象类型的值连接时,首先会调用对象中的toString()方法得到一个字符串,然后再进行两个字符串的连接运算:
Double d=new Double(33.34); // d是一个对象 String aStr="value="+d; // aStr="value=33.34"
注意:每个对象中均有一个toString()方法,该方法返回对象的一个字符串形式的描述。
2.3.2 修改字符串
每个字符串都具有一个长度,可以使用字符串对象的实例方法length()来取得字符串的长度:
String aStr="HelloWorld"; int size=aStr.length(); //size的值为10
如果想知道字符串aStr中第i(0<i<aStr.length()-1)个位置的字符值是什么,使用实例方法charAt(i)来返回一个字符值,例如:
String aStr="HelloWorld"; char aChar=aStr.charAt(0); //aChar= 'H'
注意:Java语言中,字符串中字符的下标索引是从0开始的。
还可以使用substring()方法来获取一个字符串的子串。例如:
String aStr="HelloWorld"; String subStr=aStr.substring(0,4); //subStr="Hell";
前面我们已经提到:字符串被创建后,其中的内容不能再改变。如果要改变字符串的内容,需要重新生成新的字符串对象。即字符串是不可改变的对象,也就是说字符串对象不提供方法用以修改字符串的内容。
但是Java语言中提供了一个StringBuffer类,该类所生成的字符串对象提供了修改字符串内容的方法(如append()),无须重新生成对象即可改变字符串的内容,例如:
StringBuffer aStr=new StringBuffer("HelloWorld"); // ① aStr=aStr.append("!"); // ② aStr="HelloWorld!"
上面的代码片段中,字符串的内容进行了修改,但是并不需要生成新的对象,如图2.5所示。

图2.5 改变StringBuffer对象中的内容
在执行完语句①和②之后,aStr指向的是同一个对象,只是对象中存储的字符串内容有了变化。
2.3.3 判断字符串是否相等
如果需要判断两个字符串的内容是否相等,读者可能立刻会想到使用关系运算符==,例如:
String aStr="HelloWorld!"; String bStr="HelloWorld!"; if(aStr==bStr) { //错误 ... }
然而这种判断方式是不可靠的,即aStr==bStr有可能返回true,也有可能返回false(依赖于Java虚拟机)。这显然是不对的。为什么呢?
由于字符串是不可改变的对象,因而有的Java虚拟机对相同的字符串实现共享;而有的Java虚拟机对相同的字符串则不共享,如图2.6所示。

图2.6 字符串存储的两种模式
又由于字符串变量中存储的是所指向的字符串对象的地址值(所有的对象变量中存储的值都是其所指向的对象在内存中的地址值)。因而,在共享模式下,aStr==bStr的返回值是true(因为是同一个地址值);而在非共享模式下,aStr==bStr的返回值是false。也就是说,用关系运算符==来判断字符串是否相等是不可行的。
正确判断两个字符串内容是否相等时使用equals()方法,例如:
String aStr="HelloWorld!"; String bStr="HelloWorld!"; if(aStr.equals(bStr)){ //正确 ... }
2.3.4 使用帮助文档
Java开发包中提供了几千个类,方法更是数以万计,要想全部记住这些类和方法是不现实的。因此,学会如何使用帮助文档就很有必要。读者可以从甲骨文公司的网站(https://docs.oracle.com/javase/7/docs/api/)免费下载帮助文件。
下载得到的帮助文件是一个压缩格式的文件,使用适当的解压缩工具(Winzip等)解压后,会发现释放文件中存在一个docs目录。双击打开,进入帮助文档的起始页面(见图2.7)。该页面被分隔成三个窗格:左上角的窗格显示的是Java所提供的包名;左下角的窗格中显示的是所选中包中的所有类和接口名;单击左下角窗格中的类或是接口名,将会在右边的窗格中显示该类或是接口的详细帮助信息。

图2.7 帮助文档(1)
可以采用不同的策略来查找我们所需要的帮助信息,下面通过几个例子来说明。
问题:查看String类中的charAt()方法的详细使用信息。
方法一:如果已经知道String类位于java.lang包中,那么单击左上角窗格中的java.lang包名,这时候,会在左下角的窗格中显示出java.lang包中的所有接口和类,在该窗格中找到并单击String超链接,就会在右边的窗格中显示出String类的详细信息。滚动该窗格,就可以找到charAt()方法的详细使用信息,如图2.8所示。

图2.8 帮助文档(2)
方法二:如果不知道String类位于哪个包中,那么可以单击帮助文档起始页面(见图2.7)右边窗格中的Index超链接。这时候,右边的窗格中就会出现按字母排序的方式显示的帮助文档内容,如图2.9所示。

图2.9 帮助文档(3)
由于String的首字符是S,所以单击S超链接,在右边的窗格中就会显示所有以S为首字符的类、接口或是变量的帮助信息,如图2.10所示。

图2.10 帮助文档(4)
滚动该窗格,可以找到超链接String,单击该超链接,即可进入String类的详细帮助页面。
方法三:如果只记得方法名charAt(),不知道是哪个类中的方法,这时候,可以首先进入按字符排序的页面,单击超链接C(由于charAt()方法的首字符为c),然后滚动右边的窗格,即可找到一个合适的charAt()方法,如图2.11所示。

图2.11 帮助文档(5)