Java 的 Hello World 代码
public class HelloWorld { /** * * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("Hello World"); } }
编译运行
$ javac HelloWorld.java $ java HelloWorld Hello World
功能就是在控制台打印 Hello World 字符串, 我们这里深入每一个步骤,探讨是如何将字符串打印到控制台的。
环境
我们刚才的程序运行在 Ubuntu Linux 的控制台 bash 程序里。 javac 是编译器, java 运行虚拟机,载入 HelloWorld.class 执行 HelloWorld 类的 main 函数,这部分是属于虚拟机的内容,暂时不做考虑,我们主要从代码调用的步骤分析。
System 类
从代码逻辑上,我们很容易看出是 System 类的 out 成员 println 函数执行了打印操作:
public final class System { /** * Default input stream. */ public static final InputStream in; /** * Default output stream. */ public static final PrintStream out; /** * Default error output stream. */ public static final PrintStream err; private static final String lineSeparator; private static Properties systemProperties; static { err = new PrintStream(new FileOutputStream(FileDescriptor.err)); out = new PrintStream(new FileOutputStream(FileDescriptor.out)); in = new BufferedInputStream(new FileInputStream(FileDescriptor.in)); lineSeparator = System.getProperty("line.separator"); }
out 是个 PrintStream
PrintStream 类
/** * Prints a string followed by a newline. The string is converted to an array of bytes using * the encoding chosen during the construction of this stream. The bytes are * then written to the target stream with {@code write(int)}. * * <p>If an I/O error occurs, this stream's error state is set to {@code true}. * * @param str * the string to print to the target stream. * @see #write(int) */ public synchronized void println(String str) { print(str); newline(); }
具体的工作交给了 print , 我们在这个类里面可以看到 newline 只是打印了两个特殊字符,换行。
public synchronized void print(String str) { if (out == null) { setError(); return; } if (str == null) { print("null"); return; } try { if (encoding == null) { write(str.getBytes()); } else { write(str.getBytes(encoding)); } } catch (IOException e) { setError(); } }
进一步的工作由 write 函数完成:
public synchronized void write(int oneByte) { if (out == null) { setError(); return; } try { out.write(oneByte); int b = oneByte & 0xFF; // 0x0A is ASCII newline, 0x15 is EBCDIC newline. boolean isNewline = b == 0x0A || b == 0x15; if (autoFlush && isNewline) { flush(); } } catch (IOException e) { setError(); } }
又来了个 out 这个,out 是 来自 OutputStream 的实现类 public class FileOutputStream extends OutputStream
public class FileOutputStream extends OutputStream { private FileDescriptor fd; private final boolean shouldClose; /** The unique file channel. Lazily initialized because it's rarely needed. */ private FileChannel channel; /** File access mode */ private final int mode; private final CloseGuard guard = CloseGuard.get();
FileDescriptor
public final class FileDescriptor { /** * Corresponds to {@code stdin}. */ public static final FileDescriptor in = new FileDescriptor(); /** * Corresponds to {@code stdout}. */ public static final FileDescriptor out = new FileDescriptor(); /** * Corresponds to {@code stderr}. */ public static final FileDescriptor err = new FileDescriptor(); /** * The Unix file descriptor backing this FileDescriptor. * A value of -1 indicates that this FileDescriptor is invalid. */ private int descriptor = -1; static { in.descriptor = STDIN_FILENO; out.descriptor = STDOUT_FILENO; err.descriptor = STDERR_FILENO; }
STDIN_FILENO等是文件描述符,是非负整数,一般定义为0, 1, 2,属于没有buffer的I/O,直接调用系统调用,在<unistd.h>。
参考i: http://blog.csdn.net/xiaoxi2xin/article/details/5524769
@Override public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException { IoBridge.write(fd, buffer, byteOffset, byteCount); } @Override public void write(int oneByte) throws IOException { write(new
最后是调用 os 的 write