简体   繁体   English

为什么 Java 中的 System.out.println() 会打印到控制台?

[英]Why does System.out.println() in Java print to the console?

I read several posts online explaining what System.out.println() is in Java.我在网上阅读了几篇文章,解释了 Java 中的System.out.println()是什么。 Most of them go like this:他们中的大多数 go 像这样:

  • System is a final class in the java.lang package. System是java.lang package中的final java.lang
  • out is a public static object inside the System class of type PrintStream . out是类型为PrintStreamSystem class 内的public static object 。
  • println() prints a line of text to the output stream. println()将一行文本打印到 output stream。

My question is when we do System.out.println() in our code, why does it end up writing to the console?我的问题是当我们在代码中执行System.out.println()时,为什么它最终会写入控制台? This article explains how we can make it write to a file by calling System.setOut() . 本文解释了我们如何通过调用System.setOut()将其写入文件。 So my question translates to where is System.setOut() called to redirect its output to the console?所以我的问题转化为调用System.setOut()以将其 output 重定向到控制台的位置?

I checked System.setOut() 's source .我检查了System.setOut()source It makes a call to setOut0() which is a native method.它调用native方法setOut0() This method is directly called inside the initializeSystemClass() method by passing it fdOut which is a FileOutputStream defined here .此方法在initializeSystemClass()方法中直接调用,方法是将 fdOut 传递给它, fdOut此处定义的FileOutputStream I did not find a console output stream passed to setOut0() anywhere, nor did I find a call to the non-native setOut() done anywhere.我没有在任何地方找到传递给setOut0()的控制台 output stream,也没有在任何地方找到对非本地setOut()的调用。 Is it done somewhere else outside the System class by the JVM while starting execution?它是否在开始执行时由 JVM 在System class 之外的其他地方完成? If so, can someone point me to it?如果是这样,有人可以指出我吗?

My doubt is when we do System.out.println() in our code, why it ends up in writing to console?我的疑问是当我们在代码中执行System.out.println()时,为什么它最终会写入控制台?

In any POSIX compliant shell, each process gets three "standard" streams when the shell starts it:在任何符合 POSIX 的 shell 中,当 shell 启动时,每个进程都会获得三个“标准”流:

  • The "standard input" stream is for reading input. “标准输入” stream 用于读取输入。
  • The "standard output" stream is for writing ordinary output. “标准输出”stream是写普通output用的。
  • The "standard error" stream is for writing error output. “标准错误” stream 用于写入错误 output。

(The same idea is also used in many non-POSIX compliant shells as well.) (同样的想法也用于许多非 POSIX 兼容的 shell。)

For an interactive POSIX shell, the default is for these streams to read from and write to the shell's "console"... which could be a physical console, but is more likely to be a "terminal emulator" on the user's (ultimate) desktop machine.对于交互式POSIX shell,默认情况下这些流可以读取和写入 shell 的“控制台”......这可能是物理控制台,但更有可能是用户(最终)上的“终端模拟器”台式机。 (Details vary.) (细节有所不同。)

A POSIX shell allows you to redirect the standard streams in various ways; POSIX shell 允许您以各种方式重定向标准流; eg例如

$ some-command < file     # read stdin from 'file'
$ some-command > file     # write stdout to 'file'
$ some-command 2> file    # write stderr to 'file'
$ some-command << EOF     # read stdin from a 'here' document
  lines of input
  ...
  EOF
$ some-command | another  # connect stdout for one command to
                          # stdin for the next one in a pipeline

and so on.等等。 If you do this, one or more of the standard streams is NOT connected to the console.如果您这样做,一个或多个标准流不会连接到控制台。

Further reading:进一步阅读:


So how does this relate to the question?那么这与问题有什么关系呢?

When a Java program start, the System.in/out/err streams are connected to the standard input / output / error streams specified by the parent process;当一个Java程序启动时, System.in/out/err /out/err流连接到父进程指定的标准输入/output/错误流; typically a shell.通常是 shell。

In the case of System.out , that could be the console (however you define that) or it could be a file, or another program or... /dev/null .System.out的情况下,它可能是控制台(无论您如何定义),也可能是一个文件、另一个程序或... /dev/null But where the output goes is determined by how the JVM was launched.但是 output 的去向取决于 JVM 的启动方式。

So, the literal answer is "because that is what the parent process has told the Java program to do".因此,字面上的答案是“因为这是父进程告诉 Java 程序要做的事情”。


How internally shell communicates with jvm to set standard input / output in both Windows and Linux? How internally shell communicates with jvm to set standard input / output in both Windows and Linux?

This is what happens with Linux, UNIX, Mac OSX and similar.这就是 Linux、UNIX、Mac OSX 和类似设备会发生的情况。 (I don't know for Windows... but I imagine it is similar.) (我不知道 Windows ......但我想它是相似的。)

Suppose that the shell is going to run aaa > bbb.txt .假设 shell 将运行aaa > bbb.txt

  1. The parent shell forks a child process... sharing the parent shell's address space.父 shell 分叉一个子进程...共享父 shell 的地址空间。
  2. The child process closes file descriptor 1 (the standard output file descriptor)子进程关闭文件描述符1(标准output文件描述符)
  3. The child process opens "bbb.txt" for writing on file descriptor 1.子进程打开“bbb.txt”以写入文件描述符 1。
  4. The child process execs the "aaa" command, and it becomes the "aaa" command process.子进程执行“aaa”命令,成为“aaa”命令进程。 The file descriptors 0, 1, and 2 are preserved by the exec call.文件描述符 0、1 和 2 由 exec 调用保留。
  5. The "aaa" command starts... “aaa”命令开始...

When the "aaa" command starts, it finds that file descriptors 0 and 2 (stdin and stderr) refer to the same "file" as the parent shell.当“aaa”命令启动时,它发现文件描述符 0 和 2(stdin 和 stderr)引用了与父 shell 相同的“文件”。 File descriptor 1 (stdout) refers to "bbb.txt".文件描述符 1 (stdout) 指的是“bbb.txt”。

The same thing happens when "aaa" is the java command.当“aaa”是java命令时,也会发生同样的事情。

It doesn't need to.它不需要。 We can redirect to somewhere else.我们可以重定向到其他地方。 Here is the code to re-direct into the file:这是重定向到文件的代码:

PrintStream output = new PrintStream(new File("output.txt"));
System.setOut(output);
System.out.println("This will be written to file");

By default, the console is the standard output stream (System.in) in Java.默认情况下,控制台是Java中的标准output stream(System.in)。

System.out.println does not print to the console, it prints to the standard output stream ( System.out is Java's name of the standard output stream). System.out.println不打印到控制台,它打印到标准 output streamSystem.out是 Java 的标准 output 流的名称)。 The standard output stream is usually the console, but it doesn't have to be.标准的 output stream 通常是控制台,但并非必须如此。 The Java runtime just wraps the standard output stream of the operating system in a nice Java object. The Java runtime just wraps the standard output stream of the operating system in a nice Java object.

A non-interactive program often uses a few standard input and output channels: it reads input from the standard input stream, does some operations on it, and produces output on the standard output stream. A non-interactive program often uses a few standard input and output channels: it reads input from the standard input stream, does some operations on it, and produces output on the standard output stream. The standard output stream can be the console, but it can also be piped to the standard input stream of another program or to a file.标准 output stream 可以是控制台,但也可以通过管道传输到另一个程序的标准输入 stream 或文件。 In the end, the operating system running the programming decides what the standard output stream output to.最后,运行编程的操作系统决定了标准 output stream output 是什么。

For example, in Unix terminals you can do something like:例如,在 Unix 终端中,您可以执行以下操作:

java -jar your.program.jar > output.txt

and store the output of your program in a text file, or并将程序的 output 存储在文本文件中,或

java -jar your.program.jar | grep hello

to only display the lines of the output which contain 'hello'.仅显示包含“hello”的 output 的行。 Only if you don't specify another destination, the standard output stream writes to the console.仅当您不指定其他目的地时,标准 output stream 才会写入控制台。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM