1、关于输入、输出的一些基本概念
在Java语言中,内容对象(字符数据、文件数据等等)的输入、输出都是以“流”(英文为stream)的形式处理的。“流”大家可以理解为一条河;河水总是从一边流向另外一边。在计算机系统中,数据也是如此,从一端流向另外一端。
以下是关于输入流和输出流的解释:
l 如果我们从数据源读取信息,称之为“输入流”(英文为input stream)。
l 如果我们向目标地写入信息,称之为“输出流”(英文为output stream)。
以文件来举例,如果我们从文件file1.txt 读取数据,则这里需要一个文件输入流(英文file input stream)来处理数据;如果我们将从file1.txt的读取结果写入到file2.txt,则需要一个文件输出流(file output stream)来处理数据。
在Java语言中,它提供了一个标准的输入流(System.in)和一个标准的输出流(System.out)。
Java 8 官方API 文档 描述如下:

注意:
在Java语言中,System.out 和 System.in 是 final 类型的,所以对象关闭后,无法再次初始化。因此,如果要进行资源回收,请确认你不再需要它后才关闭流处理。参考源码图:


2、获取键盘输入
在这个练习中,我们没有使用复杂的图形界面,只是使用较为简单的字符界面。所以,我们有2种方式可以获取键盘输入:Scanner 类 和 BufferedReader 类。下面分别说明:
l 关于BufferedReader 类
在Java 1.5(即 Java 5)以前,是没有Scanner类的。大家如果要获取键盘输入,基本都是用 BufferedReader 类,来达成想要的效果。参考代码如下:
public static void main(String[] args) throws Exception {
//创建一个读取器对象
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
//获取输入
System.out.print("请输入内容(reader方式):");
String s2 = reader.readLine();
//展示输入的内容
System.out.println("reader 读取到内容 content=("+s2+")");
//关闭输入流
reader.close();
}通过上面的代码,我们可以看出,BufferedReader 对象是通过 InputStreamReader 对象创建的,然后InputStreamReader 对象是通过 System.in 标准输入流创建的。因此,我们可以推断,在 reader.close 方法关闭读取器时,同时会关闭System.in标准输入流。
下面的截图展示了BufferedReader的一些常用方法:

l 关于Scanner 类
从Java 1.5(即 Java 5)开始,JDK提供了一个新的读取器 Scanner 类。相比于 BufferedReader,它自带了丰富的处理方法,以及更加人性化的处理方式。下面的参考代码,我们实现了刚才一样的功能:
public static void main(String[] args) throws Exception {
//创建一个读取器对象
Scanner scanner = new Scanner(System.in);
//获取输入
System.out.print("请输入内容(scanner方式):");
String s2 = scanner.nextLine();
//展示输入的内容
System.out.println("scanner 读取到内容 content=("+s2+")");
//关闭输入流
scanner.close();
}通过上面的代码,我们可以看出 Scanner 对象时通过 System.in 标准输入流创建的。因此,我们可以推断,在scanner.close 方法关闭读取器时,同时会关闭System.in标准输入流。
下面截图展示了Scanner的一些常用方法:

3、资源回收测试
在第1点中,我们谈到 System.in 是 final 类型的,关闭后,就不能再次初始化,现在我们测试一下。
public static void main(String[] args) throws Exception {
//创建一个读取器对象
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
//获取输入
System.out.print("请输入内容(reader方式):");
String s2 = reader.readLine();
//展示输入的内容
System.out.println("reader 读取到内容 content=("+s2+")");
//关闭输入流
reader.close();
//======= 这里测试再次创建读取器
reader = new BufferedReader(new InputStreamReader(System.in));
String s3 = reader.readLine();
//展示输入的内容
System.out.println("reader 读取到内容 content=("+s3+")");
}
这里从上图的运行时异常,我们可以看出,虽然重新创建了reader 对象,但是输入流是无法重新初始化了。请记住,Scanner类和BufferedReader类 只能关闭一次。