【问题标题】:out in System.out.println()在 System.out.println() 中输出
【发布时间】:2012-03-16 07:50:24
【问题描述】:

首先很遗憾,如果这是一个非常基本的问题,并且我宣传我仍然是一个代码猴子。 我在一次采访中被要求阐明 System.out.println(); 我解释了以下方式

//this class belongs to java.lang package
class System{
  public static PrintStream out;
}
//this class belongs to java.io package
class PrintStream{
 public void println..
}

我已经解释过 System.out 是有效的,因为这是我们在 java 中访问静态变量的方式,而 out 是 PrintStream 的一个对象,因此我们可以访问它的方法,总而言之

System.out.pritnln(); 

他让我模拟一个类似的程序,我跟踪它并没有工作,因为 System.out 返回 null

我的问题是在 java 中实例化的对象在哪里?如果我没记错的话,它是一个预定义的对象吗?这应该是什么细致的解释。

从技术上讲,我们应该说什么?是 PrintStream 类型的变量还是应该说它是 PrintStream 类型的对象?

【问题讨论】:

  • “System.out 返回 null”是什么意思?
  • 我创建了一个类比程序,例如 class A{ static B out}; class B{ } 我试图打印 System.out.println(A.out);返回 null。

标签: java jvm system


【解决方案1】:

System类初始化后,调用initializeSystemClass()方法,代码如下:

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));

在这段代码中setOut0()是一个在System.c中实现的原生函数:

JNIEXPORT void JNICALL
Java_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream)
{
    jfieldID fid =
        (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");
    if (fid == 0)
        return;
    (*env)->SetStaticObjectField(env,cla,fid,stream);
}

这是一个标准的 JNI 代码,它将 System.out 设置为传递给它的参数,此方法调用本机方法 setOut0() 将 out 变量设置为适当的值。

System.out 是最终变量,这意味着它不能在 initializeSystemClass() 中设置为其他值,但使用本机代码可以修改最终变量。

【讨论】:

    【解决方案2】:

    甚至没有必要去寻找网络和文档。我们可以简单地说 javap java.lang.System 这为您提供了所有静态字段的列表,属于 System 类的方法原型。 我们可以使用 javap 获取任何 java 类的详细信息,前提是您知道它的包和类名 out 是 System 类中定义的 PrintStream 的公共静态对象。

    【讨论】:

      【解决方案3】:

      System.out.pritln中的Out是System类中PrintWriter的静态字段(对象),println是PrintWriter的方法。

      参考: 系统:http://docs.oracle.com/javase/6/docs/api/java/lang/System.html 打印作者:http://docs.oracle.com/javase/6/docs/api/java/io/PrintWriter.html

      【讨论】:

        【解决方案4】:

        System.out是一个普通的静态属性,它是JVM在初始化时通过initializeSystemClass()方法设置的。您甚至可以更改它(尽管不推荐),只需调用System.setOut(printOutStream);,其中printOutStream 是您要用作标准输出的流。

        这是一个很好的article,详细说明了 System.out.println() 的工作原理。

        【讨论】:

        • 其实out是JVM通过initializeSystemClass()方法设置的。
        【解决方案5】:

        System.out 在类被实例化时被初始化为null。这是由System.java 中的nullPrintStream() 方法设置的,它只返回null

        当 JVM 初始化后,它会调用 initializeSystemClass() 方法。此方法调用native 方法setOut0()out 变量设置为适当的值。

        这可能看起来很奇怪,但它是必要的操作,原因如下:

        • out 不能静态设置为该值,因为 System 需要是第一个加载的类之一(在 PrintStream 之前)。
        • out 必须是 final,这样它的值就不能被用户直接覆盖。
        • 由于out 不能静态设置,并且是最终的,我们必须使用native 方法setOut0() 覆盖语言的语义。

        希望对你的理解有所帮助。

        【讨论】:

          【解决方案6】:

          在 Oracle Java 运行时库中,它使用 registerNatives() 本地方法本地实例化,该方法在加载 System 类时调用(通过 static 初始化程序)。然而,这是一个实现细节。

          您也可以直接使用System.setOut()设置System.out

          【讨论】:

          • 这是真的吗?因为registerNatives() 将本机方法链接到 JVM 内部方法,所以我从未见过它用于实例化变量。
          【解决方案7】:

          System.out.println();

          这里的println是printstream类的对象,我们不能直接为printstream类创建对象。 Out 是系统类的对象。 out 在系统类中称为字段。在调用 system.out 时,它间接为 printstream 类创建对象。因此我们可以使用 System.out.prontln() 调用 println() 方法。

          【讨论】:

          • 很多在这个答案中的错误陈述,几乎数不清。忽略。
          • Surendar,println() 不是一个对象,而是 PrintStream 类的一个方法。
          • 可以直接为PrintStream类创建一个对象。例如,docs.oracle.com/javase/1.5.0/docs/api/java/io/… .
          • "out" 不是 System 的特定对象,但正如您所说,它是 System 的一个字段。不是“被调用”,而是“被调用”,因为对象在 Java 中不仅仅是“拥有”对象,它比这更结构化。
          • 调用System.out时,不会间接创建PrintStream对象;当 JVM 启动并且它的引用被分配给 System.out 时,它实际上存在。 (正如上面其他一些帖子中提到的)
          【解决方案8】:

          System.out 由 JVM 提供。在调用 main 方法时,System.out 已打开并可供使用。

          http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#out

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2023-04-01
            • 2014-08-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-29
            • 2015-07-31
            相关资源
            最近更新 更多