InputSteam是所有字节流类的基类,其中有一个读取方法
public  abstract int read() 
该抽象方法应该是没有实现的,那也就是说不能直接使用。但是在System类中,有
public static final InputStream in;
我们可以通过System.in.read()读取一个字符
这个如何解释呢。

解决方案 »

  1.   

    请问楼主,这句话是什么意思啊?
    BufferedReader stdin =
          new BufferedReader(
            new InputStreamReader(System.in));
      

  2.   

    in只是声明为InputStream类型,其实是已经实现这个类的继承子类
      

  3.   

    new BufferedReader()这个构造方法是要传入一个Reader类(字符流)的实例作为参数的,
    new InputStreamReader(System.in)这句话即是把System.in这个InputStream类(字节流)的实例转化成Reader类,并将其传入作为new BufferedReader()的参数.其中System.in代表了标准输入流,即表示你从运行窗口中敲入的字符都作进入这个流了.整句话的意思是:把你从运行窗口中敲入的字符送进一个BufferedReader形成一个BufferedReader流
      

  4.   

    API上说的很清楚,System.in已经打开,public static final InputStream in ,这是它的定义,我认为把in声明为InputStream并不就真正表示它只是一个InputStream的实例,就像你可以定义一个List a,然后在实现时把a实现成ArrayList类型的
      

  5.   

    BufferedReader stdin =
          new BufferedReader(
            new InputStreamReader(System.in));
    看了这个代码,似乎有些明白,stdin就是标准输入。
    可是Java用的时候是System.in.read(); 用的就是System类中,in实例的read方法,与sdin的关系是什么?
    API上说的很清楚,System.in已经打开,public static final InputStream in ,这是它的定义,我认为把in声明为InputStream并不就真正表示它只是一个InputStream的实例,就像你可以定义一个List a,然后在实现时把a实现成ArrayList类型的
    但实际上就是用System.in.read(); 到底在什么地方实现了?
      

  6.   

    inpublic static final InputStream in
    The "standard" input stream. This stream is already open and ready to supply input data. Typically this stream corresponds to keyboard input or another input source specified by the host environment or user. 被打开了,是不是又被封装起来了,java感觉比vc还神秘。被谁打开了?打开了就只能能用了吗?是不是也被谁偷偷实现了?这个谁是谁呢?
      

  7.   

    在热心网友的点拨与讨论下,终于搜索到了答案。一开始搜不到:-)。以下是一位网友的解答,基本上可以解决问题了;
    有趣的问题.不过写java.io相关的应用其实不需要去关心这个问题的. 
    但我想还是解释一下我对这个out,in的初始化的理解好了 
    我也看了一下java.lang.System的源代码. 
    System类里有大量的native方法,是调用本地代码的,这些代码很可能是由虚拟机来调用的. 
    System类的开头有一段: 
    static { 
    registerNatives(); 

    这段代码会在虚拟机启动的时候就执行,它在虚拟机里注册System需要使用的一些本地代码 
    比如: 
    private static native Properties initProperties(Properties props); 
    private static native void setOut0(PrintStream out); 
    在windows下的话,它就告诉虚拟机到哪个dll文件里去找相应的实现 
    楼主说 
    >然而,我知道out是一个PrintStream的对象,但我查看了有关的原代码:public final static PrintStream >out = nullPrintStream(); 
    >public final static InputStream in = nullInputStream(); 
    在nullInputStream()方法里有注释解释为什么会设置为空: 
    /** 
    * The following two methods exist because in, out, and err must be 
    * initialized to null. The compiler, however, cannot be permitted to 
    * inline access to them, since they are later set to more sensible values 
    * by initializeSystemClass(). 
    */ 
    private static InputStream nullInputStream() throws NullPointerException { 
    if (currentTimeMillis() > 0) 
    return null; 
    throw new NullPointerException(); 

    也就说in, out, and err 初始化为null,然后会在后来由initializeSystemClass()方法类初始化成有意义的值 
    /** 
    * Initialize the system class. Called after thread initialization. 
    */ 
    private static void initializeSystemClass() { 
    props = new Properties(); 
    initProperties(props); 
    sun.misc.Version.init(); 
    FileInputStream fdIn = new FileInputStream(FileDescriptor.in); 
    FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out); 
    FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err); 
    setIn0(new BufferedInputStream(fdIn)); !!! 
    setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true)); !!! 
    setErr0(new PrintStream(new BufferedOutputStream(fdErr, 128), true)); !!! // Enough of the world is now in place that we can risk 
    // initializing the logging configuration. 
    try { 
    java.util.logging.LogManager.getLogManager().readConfiguration(); 
    } catch (Exception ex) { 
    // System.err.println("Can′t read logging configuration:"); 
    // ex.printStackTrace(); 
    } // Load the zip library now in order to keep java.util.zip.ZipFile 
    // from trying to use itself to load this library later. 
    loadLibrary("zip"); // Subsystems that are invoked during initialization can invoke 
    // sun.misc.VM.isBooted() in order to avoid doing things that should 
    // wait until the application class loader has been set up. 
    sun.misc.VM.booted(); 

    in,out,err就是在以上方法以下三条语句里初始化的. 
    setIn0(new BufferedInputStream(fdIn)); !!! 
    setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true)); !!! 
    setErr0(new PrintStream(new BufferedOutputStream(fdErr, 128), true)); !!! 
    看 
    private static native void setIn0(InputStream in); 
    ~~~~~~~ 
    这是个native函数,是前面registerNatives()的时候注册了的.这个函数应该是把实际连接到输入输出设备的句柄传给虚拟机并赋值给in,out,err 至于: 
    >InputStream是个抽象的类,怎么能使用char=(char)System.in.read()读入一个字符 
    我想你还没有明白什么是面向对象. 
    看看下面代码,我用OutputStream(也是抽象类,跟InputStream对应的输出类)以方便演示: 
    import java.io.IOException; 
    import java.io.OutputStream; 
    public class HelloWorld { public OutputStream out=null; public void setOutputStream(OutputStream out){ 
    this.out=out; 
    } public static void main(String[] args) throws IOException{ 
    HelloWorld h=new HelloWorld(); 
    PrintStream myOut=System.out;//System.out是一个PrintStream 
    h.setOutputStream(myOut); 
    h.out.write("hello,world".getBytes());//一般没人这么写的 


    以上代码执行后会输出hello,world 
    h.out是OutputStream,也是个抽象类,为什么能write(o)呢? 
    因为PrintStream是OutputStream的子类,所以能被"当作"OutputStream传给h.setOutputStream(myOut); 
    h.out.write执行的时候实际上是调用这个传进来的PrintStream实例的write方法 
    同样System.in和out肯定也是在initializeSystemClass()的时候被赋予了一个实际的可用的子类 
    要能体会到面向对象的好处,就要逐渐适应"对接口编程"的思想,相同接口的对象可以根据需要方便的替换. 
    比如,我刚才传了一个PrintStream,因此HelloWorld输出到了屏幕上. 我如果传给OutputStream的另一个子类FileOutputStream,就会输出到文件里 >还有为什么不是说字符流:writer和reader一般用于UniCode的读写吗?为什么键盘的输入用reader类呢? 
    不知道你在哪里看到说writer和reader一般用于UniCode的读写 >最近正在看java.io包,晕死!里面用到了很多包装器,这个包装那个,那个又包装这个的,简直要崩溃 
    看一下设计模式--Decorator(装饰)模式,你就明白了 另外一个网友写了这么一句话
    System.out.println("变量System.in引用的对象的类是:"+System.in.getClass().getName()); 输出:变量System.in引用的对象的类是:java.io.BufferedInputStream
    那么,说明in实际上是BufferedInputStream类的实例。所以可以调用read()方法。