字符串是由一串字符( char类型的值)组成的。一个string类型的字面量包括一对双引号和其中的字符,比如"Hello, World"。 String类型是Java的一个数据类型, 但并不是原始数据类型。
和各种原始数据类型一样, Java 内置了一个串联String类型字符串的运算符(+)。拼接两个String类型的字符串将得到一个新的String值,其中第一个字符串在前,第二个字符串在后。
类型 | 值域 | 举例 | 运算符 | 表达式 | 值 |
---|---|---|---|---|---|
String | 一串字符 | “AB” | +(拼接) | “1”+”+”+ "2” | “1+2” |
“2.5” | “Hi,”+“Bob” | “Hi,Bob” |
字符串的两个主要用途分别是将用户从键盘输入的内容转换成相应数据类型的值以及将各种数据类型的值转化成能够在屏幕上显示的内容。Java 的String类型为这些操作内置了相应的方法,而且Integer和Double库还包含了分别和String类型相互转化的静态方法(见表1.1.12)。
public class Integer | |
---|---|
static int parseInt(String s) | 将字符串s转换为整数 |
static string toString(int i) | 将整数i转换为字符串 |
public class Double | |
static double parseDouble(String s) | 将字符串s转换为浮点数 |
static String toString(double x) | 将浮点数x转换为字符串 |
我们很少明确使用刚才提到的toString()方法,因为Java在连接字符串的时候会自动将任意数据类型的值转换为字符串:如果加号(+)的一个参数是字符串,那么Java会自动将其他参数都转换为字符串(如果它们不是的话)。这种机制也使我们能够通过一个空字符串"”将任意数据类型的值转换为字符串值。
在Java中字符串的一个重要的用途就是使程序能够接收到从命令行传递来的信息。这种机制很简单。当你输入命令java和一个库名以及一系列字符串之后,Java 系统会调用库的main()方法并将那一系列字符串变成一个数组作为参数传递给它。例如,BinarySearch 的main()方法需要一个命令行参数,因此系统会创建一个大小为1的数组。程序用这个值,也就是args[0],来获取白名单文件的文件名并将其作为StdIn. readInts()的参数。另一种在我们的代码中常见的用法是当命令行参数表示的是数字时,我们会用parseInt()和parseDouble()方法将其分别转换为整数和浮点数。
我们的标准输入、输出和绘图库的作用是建立一个Java程序和外界交流的简易模型。在模型中,Java 程序可以从命令行参数或者一个名为标准输入流的抽象字符流中获得输入,并将输出写入另一个名为标准输出流的字符流中。默认情况下,命令行参数、标准输入和标准输出是和应用程序绑定的,而应用程序是由能够接受命令输人的操作系统或是开发环境所支持。我们笼统地用终端来指代这个应用程序提供的供输入和显示的窗口。20世纪70年代早期的Unix系统已经证明我们可以用这个模型方便直接地和程序以及数据进行交互。
终端窗口包含一个提示符, 通过它我们能够向操作系统输入命令和参数。我们会经常使用java命令来运行我们的程序。我们在1.1.8.4节中提到过,Java类都会包含一个静态方法main(),它有一个 String数组类型的参数args[]。这个数组的内容就是我们输入的命令行参数,操作系统会将它传递给Java。Java和操作系统都默认参数为字符串。如果我们需要的某个参数是数字,我们会使用类似Integer . parseInt()的方法将其转换为适当的数据类型的值。
命令 | 参数 | 作用 |
---|---|---|
javac | java文件名 | 编译Java程序 |
java | .class 文件名(不需要扩展名)和命令行参数 | 运行Java程序 |
more | 任意文本文件名 | 打印文件内容 |
我们的StdOut库的作用是支持标准输出。一般来说,系统会将标准输出打印到终端窗口。print() 法会将它的参数放到标准输出中; println()方法会附加一个换行符; printf()方法能够格式化输出。
public class StdOut | |
---|---|
static void print(String s) | 打印s |
static void printIn(String s) | 打印s并接一个换行符 |
static void println() | 打印一个换行符 |
static void printf(String f, … .) | 格式化输出 |
标准输入输出使我们能够利用许多操作系统都支持的命令行的扩展功能。只需要向启动程序的命令中加入一个简单的提示符,就可以将它的标准输出重定向至一个文件。 文件的内容既可以永久保存也可以在之后作为另一个程序的输入:
% java RandomSeq 1000 100.0 200.0> data.txt
这条命令指明标准输出流不是被打印至终端窗口,而是被写入一个叫做data.txt的文件。每次调用print()或是println()都会向该文件追加一段文本。在这个例子中,我们最后会得到一个含有1000个随机数的文件。终端窗口中不会出现任何输出:它们都被直接写入了“>” 号之后的文件中。这样我们就能将信息存储以备下次使用。请注意不需要改变RandomSeq的任何内容——它使用的是标准输出的抽象,因此它不会因为我们使用了该抽象的另一 种不同的实现而受到影响。类似,我们可以重定向标准输人以使StdIn 从文件而不是终端应用程序中读取数据:
% java Average < data. txt
这条命令会从文件data.txt中读取一系列数值并计算它们的平均值。具体来说,“<” 号是一个提示符,它告诉操作系统读取文本文件data.txt 作为输入流而不是在终端窗口中等待用户的输入。当程序调用StdIn. readDouble()时,操作系统读取的是文件中的值。将这些结合起来,将一个程序的输出重定向为另一个程序的输入叫做管道:
% java RandomSeq 10000 100.0 200.0 1 java Average
这条命令将RandomSseq的标准输出和Averge的标准输入指定为同一个流。 它的效果是好像在Average运行时RandomSeq将它生成的数字输入了终端窗口。这种差别影响非常深远,因为它突破了我们能够处理的输入输出流的长度限制。例如,即使计算机没有足够的空间来存储十亿个数,我们仍然可以将例子中的1000换成1 000 000 000 。 当RandomSeq调用StdOut. printIn()时,它就向输出流的末尾添加了一个字符串; 当Averge调用StdIn.readInt() 时,它就从输入流的开头删除了一个字符串。这些动作发生的实际顺序取决于操作系统:它可能会先运行RandomSeq并产生一些输出, 然后再运行Average,来消耗这些输出,或者它也可以先运行Average,直到它需要一些输入然后再运行RandomSeq来产生一些输出。虽然最后的结果都一样, 但我们的程序就不为标准输入再需要担心这些细节,因为它们只会和标准输入和标准输出的抽象打交道。