1.字符串类String
在很多语言中,字符串都被当做字符数组来处理,但是在Java中,字符串是一个对象。String类中有11个构造方法以及40多个处理字符串的方法。
从字符串直接量创建字符串:
String
newString = new String(stringLiteral);
Java将字符串直接量看做是String对象,故下面的语句是合法的:
String
message = "Welcome to Java!";
还可以用字符数组创建一个字符串:
char[]
charArray = {'G', 'o', 'o', 'd', ' ', 'D', 'a', 'y'};
String
message = new String(charArray);
注意:String变量存储的是对String对象的引用,String对象里存储的才是字符串的值。严格地讲,术语String变量、String对象和字符串值是不同的。但在大多数情况下,他们之间的区别是可以忽略的。为简单起见,术语字符串通常用来指String变量、String对象和字符串的值。
String对象是不可变的,它的内容是不能改变的。
因字符串在程序设计中是不可变的,但同时又会频繁地使用,所以Java虚拟机为了提高效率并节约内存,对具有相同字符串序列的字符串直接量使用同一个实例。称为限定的(interned)。
1)字符串的比较
注意:运算符==只能检测两个字符串是否指向同一个对象,但它不会告诉你他们的内容是否相同。用equals
警告:如果使用像>、>=、
注意:如果两个字符串相等,equals方法返回true;如果它们不等,方法返回false。compareTo方法会根据一个字符串是否等于、大于或小于另一个字符串,分别返回0、正整数或负整数。
2)字符串长度、字符以及组合字符串
警告:length()是String类的一个方法,但它是数组对象的一个属性。所以,要获取字符串的字符个数,就必须使用s.length(),而要获取数组a中的元素个数,就必须使用a.length。
注意:使用一个字符串时,往往是知道他的直接量值的。为方便起见,Java允许在不创建新变量的情况下,使用字符串直接量直接引用字符串。这样,"Welcome
to Java".charAt(0)是正确的,它返回W。
注意:在计算机内部,字符串的值时用私有数组变量表示的。数组是不能从String类的外部访问的。String类提供了许多像length()和charAt(index)这样的公共方法以获取该数组的信息。这是一个关于封装的很好的例子:累的数据域通过私有修饰符对用户隐藏,这样,用户就不能直接操作数据域。如果数组不是私有的,用户就能通过修改数组而改变字符串的内容,这就会违反String类不可变的原则。
警告:在字符串S中越界访问字符是一种常见的程序设计错误——StringIndexOutOfBoundsException异常。
3)获取子串
注意:如果beginIndex就是endIndex,那么substring(beginIndex,
endIndex)就会返回一个长度为0的空字符串。如果beginIndex > endIndex,
就会出现运行错误。
4)字符串的转换、替换和分隔
这些方法返回一个源自原始字符串的新字符串(并未改变原始字符串!)。
5)依照模式匹配、替换和分隔
可以通过指定某个模式来匹配、替换或分隔一个字符串,这是一种非常有用且功能强大的特性,通常称为正则表达式(regular
expression)。
String类中的matches方法:不仅可以匹配定长的字符串,还能匹配一套遵从某种模式的字符串。
eg:正则表达式"Java.*"描述的字符串模式是以字符串Java开始的,后面紧跟任意0个或多个字符。
方法replaceAll、replaceFirst和split也可以和正则表达式结合在一起使用。
eg:用字符串NNN替换"a+b$#c"中的$、+或者#,然后返回一个新字符串。
这个正则表达式[$+#]表示能够匹配$、+或者#的模式,故输出是aNNNbNNNNNNNc。
将字符串分隔为由标点符号分隔开的字符串数组。
这个正则表达式[.,:;?]指定的模式是指匹配.、,、:、;或者?。这里的每个字符都是分隔字符串的分隔符。因此,这个字符串就被分隔成Java、C、C#和C++,他们都存储在数组tokens中。
6)找出字符串中的某个字符或者某个子串
String类提供了几个重载的indexOf和lastIndexOf方法,它们可以在字符串中找出一个字符或一个子串。
7)字符串与数组之间的转换
可以使用toCharArray方法。
eg:
也可以使用方法getChars(int srcBegin,int srcEnd,char[] dst,int
dstBegin)将下标从srcBegin到srcEnd-1的子串复制到字符数组dst中下标从dstBegin开始的位置。
eg:
这样,dst就变成了
为了将一个字符数组转换成一个字符串,应该使用构造方法String(char[])
或者方法valueOf(char[])。
eg:
7)将字符和数值转换成字符串
使用静态的valueOf方法能够将字符数组转换成字符串。可以使用valueOf方法的几种重载版本将字符和数值转换成字符串。
注意:可以使用Double.parseDouble(str)或者Interger.parseInt(str)将一个字符串转换成Double型值或int型值。
8)格式化字符串
String类的静态format方法可以创建一个格式化的字符串。调用方法:
String.format(format,item1,item2,...,itemk)
eg:
2.字符类Character
Java为每一种基本数据类型都提供了一个包装类。这些类是Character、Boolean、Byte、Short、Integer、Long、Float和Double,它们分别对应基本类型char、boolean、byte、short、int、long、float和double、这些类都在java.lang包中。它们把基本类型数据值当作对象处理。它们还包含一些有用的处理基本数据值的方法。
Character类有一个构造方法和多个确定字符类别(大写字母、小写字母、数字等)的方法,以及将大写字母转换成小写字母或者将小写字母转换成大写字母的方法。
3.StringBuilder/StringBuffer类
StringBuilder/StringBuffer类是可以替代String类的另一种处理字符串的解决方案。一般来说,只要使用字符串的地方,都可以使用StringBuilder/StringBuffer类。
StringBuilder/StringBuffer类比String类更灵活,可以给一个StringBuilder或者StringBuffer中添加、插入或追加新的内容,但是String对象一旦创建,它的值就确定了。
除了StringBuffer中修改缓冲区的方法是同步的之外,StringBuilder类与StringBuffer类是很相似的。如果是多任务并发访问,就使用StringBuffer;如果是单任务访问,使用StringBuilder会更有效。StringBuffer和StringBuilder中的构造方法和其他方法几乎是完全一样的。
StringBuilder类有3个构造方法和30多个用于管理生成器或修改生成器内字符串的方法。可以使用构造方法创建一个空的字符串生成器或从一个字符串创建一个字符串生成器。
可以使用StringBuffer替换StringBuilder,程序可以不经任何修改进行编译和运行。
1)修改StringBuilder中的字符串
除了setCharAt()方法之外,所有这些进行修改的方法都做了两件事:
•改变字符串生成器的内容
•返回字符串生成器的引用
提示:如果一个字符串不需要任何改变,则使用String类而不使用StringBuffer类。Java可以完成对String类的优化,例如共享限定字符串等。
2)toString、capacity、length、setLength和charAt方法
StringBuilder类提供了许多其他处理字符串生成器和获取它的属性的方法。
容量:在不增加生成器大小的情况下,能够存储的字符数量。
注意:字符串的长度总是小于或等于生成器的容量。长度是存储在生成器中的字符串的实际大小,而容量是生成器的当前大小。如果有更多的字符添加到字符串生成器,超出它的容量,则生成器的容量就会自动增加。在计算机内部,字符串生成器是一个字符数组,因此生成器的容量就是数组的大小。若果超出生成器的容量,就用新的数组替换现有数组。新数组的大小为
2*(前一个数组的长度+1)。提示:可以使用new
StringBuilder(initialCapacity)创建指定初始容量的StringBuilder。仔细选择初始容量,能够使程序更有效。如果容量总是超过生成器的实际长度,JVM将永远不需要为生成器重新分配内存。另一方面,如果容量过大,将会浪费内存空间。可以使用trimToSize()方法将容量降到实际的大小。
4.命令行参数
main方法具有String[]类型参数args,可以通过传递实参来调用一个普通方法,也可以给main方法传递参数。
运行程序时,可以从命令行给main方法传递字符串参数。
eg:用三个字符串arg0、arg1、arg2启动程序TestMain:
java
TestMain arg0 arg1 arg2
其中,参数arg0、arg1和arg2都是字符串,但是在命令行中出现时,用双引号括住它们是没有必要的。这些字符串用空格分隔。如果字符串包含空格,那就必须使用双引号括住。
当调用main方法时,Java解释器会创建一个数组存储命令行参数,然后将该数组的引用传递给args。
eg:如果调用具有n个参数的程序,Java解释器创建一个数组:
args =
new String[n];
然后,Java解释器传递参数args去调用main方法。
注意:如果运行程序时没有传递字符串,那么使用new
String[0]创建数组。在这种情况下,该数组是长度为0的空数组。args是对这个空数组的引用。因此,args不是null,但是args.length是0。
注意:在命令行输入乘法,用"*"代替*。
符号*
用于命令行时,表示当前目录下的所有文件。所以为了明确说明乘法运算符,在命令行必须用双引号括住符号*。
5.文件类File
为了能够永久地保存程序中创建的数据,需要将它们存储在磁盘或光盘上的文件中。这些文件可以传送,也可以随后被其他程序使用。
绝对文件名(absolute file name):有文件名和它的完整路径以及驱动器字母组成
绝对文件名是依赖机器的。
File类特意提供了一种抽象,这种抽象是指以不依赖机器的方式来处理很多文件和路径名依赖机器的复杂问题。File类包含很多获取文件属性的方法以及重命名和删除文件的方法;但是File类不包含读写文件内容的方法。
警告:在Windows中目录的分隔符是反斜杠(\)。但是在Java中,反斜杠是一个特殊的字符,应该写成\\的形式。
注意:构建一个File实例并不会在机器上创建一个文件。不管文件是否存在,都可以创建任意文件名的File实例。可以调用File实例上的exists()方法来判断这个文件是否存在。
在程序中,不要直接使用绝对文件名。使用绝对文件名的程序在Windows上能工作,但是不能再其他平台上工作。应该使用与当前目录相关的文件名。斜杠(/)是Java的目录分隔符(和Linux系统一样)。使用非绝对文件名的程序在Windows、Linux或任何其他系统上都能工作。
注意:Windows平台和Linux平台的路径命名习惯是不一样的。
6.文件输入和输出
File对象封装了文件或路径的属性,但是它既不包括创建文件,也不包括从(向)文件读(写)数据的方法。为了完成I/O操作,需要使用恰当的Java
I/O类创建对象。
1)使用PrintWriter写数据
调用PrintWriter的构造方法可能会抛出某种I/O异常。Java强制要求编写代码来处理这类异常。只要在方法头声明中声明throws
Exception即可。
System.out是控制台的标准Java对象。
必须使用close()方法关闭文件,如果没有调用该方法,数据就不能正确地保存在文件中。
2)使用Scanner读数据
Scanner可以将输入分为空白字符分隔的有用信息。
没有必要关闭输入文件,但这样做是一种释放被文件占用的资源的好方法。
3)Scanner如何工作
方法nextByte()、nextShort()、nextInt()、nextLong()、nextFloat()、nextDouble()和next()等都称为令牌读取方法(token-reading
method),因为他们会读取用分隔符分隔开的令牌。默认情况下,分隔符是空格。可以使用useDelimiter(String
regex)方法设置新的分隔符模式。
一个令牌读取方法首先跳过任意分隔符(默认情况下是空格),然后读取一个以分隔符结束的令牌。然后,对应于nextByte()、nextShort()、nextInt()、nextLong()、nextFloat()和nextDouble(),这个令牌就分别被自动地转换为一个byte、short、int、long、float或double型的值。对于next()方法而言是无须做转换的。如果令牌和期望的类型不匹配,就会抛出一个运行异常java.util.InputMismatchException;如果期望类型的令牌不存在,就会抛出一个运行异常java.util.NoSuchElementException。
next()方法读取一个由分隔符分隔的字符串,而nextLine()读取一个以行分隔符结束的行。
为了得到特定平台上的行分隔符,使用
String
lineSeparator = System.getProperty("line.separator");
如果从键盘输入,每行就以回车键(Entry key)结束,它对应于\n字符。
令牌读取方法不能读取令牌后面的分隔符。如果在令牌读取方法之后调用nextLine(),该方法读取从这个分隔符开始,到这行的行分隔符结束的字符。这个行分隔符也被读取,但是它不是nextLine()返回的字符串部分。
nextLine()方法会在读取行分隔符之后结束,然后返回在行分隔符之前的字符串。
eg:P284 两个例子
7.(GUI)文件对话框
Java提供javax.swing.JFileChooser类来显示文件对话框,在这个对话框中,用户可以选择一个文件。
showOpenDialog(null)方法显示一个对话框,返回一个int型值,或者是APPROVE_OPTION或者是CANCEL_OPTION,他们分别点击Open按钮或者点击Cancel按钮。
getSelectedFile()方法返回从文件对话框中选中的文件。
复习题
使用File类能够获得文件的大小(字节数)吗? P290
编程练习题
变位词(anagram):如果在不计顺序的情况下两个单词含完全相同的字母,则称这两个词互为变位词。
1)将二进制数转换为十六进制数9_9 P292
2)游戏:刽子手9_31 P295
3)生物信息方面:找出基因9_35 P296
生物学家使用字母A、C、T和G构成的序列来对基因组进行建模。基因是基因组的一个子串,基因组在三字符ATG之后开始,在三字符TAG、TAA和TGA之前结束。因此,基因字符串的长度是3的倍数,而基因不包含任何ATG、TAG、TAA和TGA这样的三字符。