【问题标题】:how Scanner class works with user defined class as inputScanner 类如何使用用户定义的类作为输入
【发布时间】:2013-08-15 10:43:44
【问题描述】:
最近,我在一本关于将用户定义的类作为输入传递给扫描仪的书中读到,但它并没有解释它背后的逻辑。这是程序
import java.nio.CharBuffer;
import java.util.Random;
import java.util.Scanner;
class ScannerInputBase implements Readable
{
private int count;
Random rand = new Random();
ScannerInputBase(int count) { this.count = count; }
public int read(CharBuffer cb) //read is a method in Readable interface
{
if(count-- == 0)
return -1;
for(int i=0;i<2;i++)
{ cb.append('a'); }
return 1;
}
}
public class ScannerInput {
public static void main (String args[]) {
Scanner input = new Scanner(new ScannerInputBase(5));
while(input.hasNext())
{
print(input.next()+"-");
}
}
}
它的输出是
aaaaaaaaaa-
我有两个问题
这里如何调用 read() 函数?
我的意思是我理解它是以某种方式被隐式调用的,但是从它被调用的地方。
输出中的单个连字符表明 main 函数中的 while 循环仅迭代一次。但为什么只有一次。我期待像aa-aa-aa-aa-aa-这样的输出
【问题讨论】:
标签:
java
java.util.scanner
【解决方案1】:
这里如何调用 read() 函数?我的意思是我明白这是
以某种方式隐式调用,但从调用位置。
答案在于方法next()的Scanner类的源代码:
public String next() {
....
while (true) {
.....
if (needInput)
readInput();
...
}
}
这将我们带到readInput方法,其定义如下:
private void readInput() {
......
try {
n = source.read(buf);
} catch (IOException ioe) {
.....
}
.....
}
我们看到readInput 方法正在调用source 对象的read 方法,该对象是Reader 类的实例,并在Scanner 的对象创建期间作为参数传递给Scanner 构造函数.
现在,由于您已将Reader 的子类对象作为参数传递给Scanner 构造函数。而且,您已经在您的班级中覆盖了read(CharBuffer) 方法,所以
read 方法的覆盖版本正在由 Scanner.readinput 方法调用。
输出中的单个连字符表明 main 函数中的 while 循环仅迭代一次。但为什么只有一次。我期待像aa-aa-aa-aa-aa-这样的输出
因为,字符串aaaaaaaaaa 中没有空格,这是默认的分隔符模式。结果,所有字符串都在单次迭代中读取。因此,hasNext 在第一次迭代后返回 false,while 循环终止。
注意:在重写方法时始终使用 @Override 注释
在子类中。
【解决方案2】:
Scanner 类是用于读取和写入数据的流的包装类。它有几个overloaded constructors。在你的情况下:
public Scanner(Readable source) {
this(source, WHITESPACE_PATTERN);
}
被调用。因为interface Readable只有一个方法read(CharBuffer cb),ScannerInputBase是一个Instaceof Readable,所以Scanner对象只是调用Readable传入的任何一个read()方法。
关于第二点,看next()的文档
从这个扫描器中查找并返回下一个完整的令牌。一种
完整的令牌之前和之后是匹配的输入
分隔符模式。此方法可能会在等待输入时阻塞
扫描,即使之前调用 hasNext() 返回 true。
使用的默认模式是:
Pattern WHITESPACE_PATTERN = Pattern.compile(
"\\p{javaWhitespace}+");
所以,它是您的扫描仪的 next() 调用,通过多次read()calls 一次性读取所有内容。