对于用Eclipse工具进行开发的程序员来说,开始学习JAVA的时候,我们会用到java.util.Scanner类来模拟界面手动输入操作,比如下面的这段代码

java frame 监听空格键 java监听控制台输入_初始化

一个让我很感兴趣的事情是,控制台输入,程序也能读取到,这是怎么办到的呢,现在让我们开启追踪模式,先找个简单的程序一行一行的去分析下,先看程序

java frame 监听空格键 java监听控制台输入_构造器_02

那我们就看红框标注内的这行代码,进入Scanner的构造器System.in就是一个InputStream  in对象,看下面的代码

java frame 监听空格键 java监听控制台输入_构造器_03

红框标注内,输入流in被初始化成了InputStreamReader,再进入到InputStreamReader的构造器,看下面的代码

java frame 监听空格键 java监听控制台输入_构造器_04

有几处红框标注,后面会用到,现在接着看,通过初始化InputStreamReader,把第二个红框标注内StreamDecoder进行了实例化sd,到此我们知道他们背地里干的什么事情,然后我们再返回来到

public Scanner(InputStream source) {
        this(new InputStreamReader(source), WHITESPACE_PATTERN);
}

这段代码告诉我们要跳转到Scanner的另一个构造器,看下面的代码

java frame 监听空格键 java监听控制台输入_java frame 监听空格键_05

这个就是真正要初始化Scanner的老窝了,this.source 就是InputStreamReader,到这里,开头的第一句代码就完事了。

我们再来看一下

java frame 监听空格键 java监听控制台输入_JVM_06

红框标注内的代码,进入到nextLine()方法内部,继续看代码

java frame 监听空格键 java监听控制台输入_初始化_07

上面红框内应该就是我们的核心代码了,继续往下看,进入到findWithinHorizon方法内部

java frame 监听空格键 java监听控制台输入_java frame 监听空格键_08

     这段代码比较有意思,第一个是绿框的内容,程序用了一个while(true)死循环,保证线程一直运行,为了等我们输入,用户线程一直等待,够哥们,  另一个是红框内的内容,needInput是个是否输入标识,如果是true的化,就会执行readInput(),这个方法就是要读取我们的输入内容,核心要接近了,再给自己点耐心,继续看代码,哈哈



java frame 监听空格键 java监听控制台输入_初始化_09

红框标注内的就是调用InputStreamReader的read(java.nio.CharBuffer target) ,InputStreamReader继承的Reader,read方法是父类Reader的,

java frame 监听空格键 java监听控制台输入_JVM_10

图中的第二个红框就是读取数据了,调用的是Reader的read(char cbuf[], int off, int len)方法,看看那个方法是啥样的呢

abstract public int read(char cbuf[], int off, int len) throws IOException;

怎么是个抽象类呢,InputStreamReader继承的Reader,所以实现了该方法,看实现代码段

public int read(char cbuf[], int offset, int length) throws IOException {
   return sd.read(cbuf, offset, length);
}

原来读取调用的是InputStreamReader里面的StreamDecoder  sd,  开始的时候我们提到过后面要用的,叫你藏,我找到你了

StreamDecoder的read方法你是怎么玩的呢,继续看代码

public int read(char ac[], int i, int j)
        throws IOException
    {
        int k = i;
        int l = j;
        Object obj = lock;
        JVM INSTR monitorenter ;
        ensureOpen();
        if(k < 0 || k > ac.length || l < 0 || k + l > ac.length || k + l < 0)
            throw new IndexOutOfBoundsException();
        if(l == 0)
            return 0;
        int i1 = 0;
        if(!haveLeftoverChar) goto _L2; else goto _L1
_L1:
        ac[k] = leftoverChar;
        k++;
        l--;
        haveLeftoverChar = false;
        i1 = 1;
        if(l != 0 && implReady()) goto _L2; else goto _L3
_L3:
        i1;
        obj;
        JVM INSTR monitorexit ;
        return;
_L2:
        if(l != 1) goto _L5; else goto _L4
_L4:
        int j1 = read0();
        if(j1 != -1) goto _L7; else goto _L6
_L6:
        i1 != 0 ? i1 : -1;
        obj;
        JVM INSTR monitorexit ;
        return;
_L7:
        ac[k] = (char)j1;
        i1 + 1;
        obj;
        JVM INSTR monitorexit ;
        return;
_L5:
        i1 + implRead(ac, k, k + l);
        obj;
        JVM INSTR monitorexit ;
        return;
        Exception exception;
        exception;
        throw exception;
}

看看这代码,原来用到了虚拟机的东西了,终于恍然大悟了,   为啥控制台等待我们的输入

JVM INSTR monitorenter ;

原来虚拟机有个监控器,在监视我们的输入内容,只要我们输入了,一回车,就读取到了CharBuffer中了

JVM INSTR monitorexit ;

虚拟机的监控器就退出了,然后我们就能读取到了内容了,我们开始的String next = sc.nextLine(); 就得到了结果。

虚拟机的东西慢慢也研究起来,暂时就是分享到这了。