一、问题背景
先看以下代码
public class practice {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
System.out.println(input);
sc.close();
practice pra = new practice();
pra.a();
Scanner sc2 = new Scanner(System.in);
input = sc2.nextLine();
System.out.println(input);
sc2.close();
}
public void a() {
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
System.out.println(input);
sc.close();
}
}
乍一看似乎没有问题,main函数中首先使用了Scanner类读入,完成输出以后关闭了流,接着调用a,a中创建Scanner类再从命令行读入,关闭流。回到main函数重复操作。但是当我们运行的时候会发现
idea报错的原因时引用了空指针,发生错误的地方是a的nextLine()方法处,明明重新创建了一个类,这是为什么呢?
二、Scanner类
执行下列代码
public class practice {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println(sc);
practice pra = new practice();
pra.a();
Scanner sc2 = new Scanner(System.in);
System.out.println(sc2);
}
public void a() {
Scanner sc = new Scanner(System.in);
System.out.println(sc);
}
}
得到输出:
java.util.Scanner[delimiters=\p{javaWhitespace}+][position=0][match valid=false][need input=false][source closed=false][skipped=false][group separator=\,][decimal separator=\.][positive prefix=][negative prefix=\Q-\E][positive suffix=][negative suffix=][NaN string=\Q?\E][infinity string=\Q∞\E]
java.util.Scanner[delimiters=\p{javaWhitespace}+][position=0][match valid=false][need input=false][source closed=false][skipped=false][group separator=\,][decimal separator=\.][positive prefix=][negative prefix=\Q-\E][positive suffix=][negative suffix=][NaN string=\Q?\E][infinity string=\Q∞\E]
java.util.Scanner[delimiters=\p{javaWhitespace}+][position=0][match valid=false][need input=false][source closed=false][skipped=false][group separator=\,][decimal separator=\.][positive prefix=][negative prefix=\Q-\E][positive suffix=][negative suffix=][NaN string=\Q?\E][infinity string=\Q∞\E]
可以发现,即使创建了三个类,他们的指向也是相同的。也就是说,我们虽然在三个地方创建了Scanner类,用流的方式从命令行读入用户输入,但只要在一个地方关闭,后面的部分均无法重新开启或是使用这个流读入,即使重新创建了这个类。
那么这是为什么呢?
用idea进行跳转我们可以看到
可以看到这里使用了static修饰,也就是说运行以后,in是一个独例,所有使用System.in的均会指向同一块引用。这也就解释了为什么创建了不同的Scanner类,关闭的是同一个流,因为他们一开始初始化的时候就是输入的同一个流。
三、修改
那么如果我不想要占用过多的内存,子类也想要从命令行读入怎么办呢?毕竟流不关闭会占用大量的资源,能够尽早关闭是最好的。那么我们可以做以下的修改,把Scanner类当作参数传给子类即可
public class practice {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
practice pra = new practice();
pra.a(sc);
String input = sc.nextLine();
System.out.println(input);
sc.close();
}
public void a(Scanner sc) {
String input = sc.nextLine();
System.out.println(input);
}
}