Java如何输出错误信息和调试信息

 在Java中输出调试信息:

在Java中输出调试信息:


而在System这个类中out和err都是定义为静态的:



而被static修饰的变量都是属于类本身的,就像这样:


可以直接被类名所调用,而不需要用对象来调用,就像这样:


要注意无论是 out 或 err 都属于 (类)PrintStream 的变量,这里就有个问题搞不懂了,比如以下这个例子:


输出结果是:空指针异常

再回头看看 System 中的out和err赋值:


API中out是被final修饰符所修饰的,而且是赋值给null啊!这不是空对象吗?这样子的话弹出空指针异常就不奇怪了,

回头看System源码,我发现其中有一个setOut()方法,如下:


out不是被final修饰符所修饰吗?怎么可以更改呢?像这个样子:


报错:,被final修饰的a不能被赋值。

那同样被final修饰的out是怎么被修改的呢?查看源码:


setOut0(out) 如下:


我发现,它们都被 native 所修饰,据我所知,Java是用C和C++实现的底层,用native修饰也就是说这个是用C和C++编写的最底层了。所以在运行 out 的时候 setOut0(PrintStream out) 方法肯定被调用过,在System源码中查找,发现在一个initializeSystemClass() 方法中setOut0 被调用了,如下:



注意备注内容:Initialize the system class.  Called after thread initialization.(初始化系统类。线程初始化后调用。

到这里已经很明白了,System 初始化之前会调用 initializeSystemClass() 方法,然后方法 initializeSystemClass() 给 out 赋值一个 新的PrintStream 对象;

所以说白了就类似与一下 out 和 err 的输出也就类似于以下内容:

public class StaticTest {

static A a;

static {
a = new A();

}

public static void main(String[] args) {
StaticTest.a.println();
}
}


class A {
public void println() {
System.out.println("Hello World");
}

}

其中 static 块中的代码会在类初始化之前就会被调用,这里用 out 输出,像这样:


输出结果:


还有一个问题就是,当 out 和 err 一起用的时候,它们并不会按着顺序来输出,比如以下:


输出结果:


再来一次,输出结果:


由于这里 println(String x) 方法是属于类 printStream 源码,以下:


这里用到了一个关键词 synchronized , 表示这是一个同步代码块,当这个同步代码块执行时,cpu是被独占的,而这里的监听器是 this ,也就是说是类本身;所以当类被调用时,先是给 out 和 err 赋值一个新的printStream对象,它们两个的对象是不同的;

所以,当我调用 mian 方法时,它们的监听器已经都生成好了,它们会一起抢占线程池,它们的先后顺序是不固定的,看谁先抢到cpu了。

但是,无论执行多少次程序,同一个监听器下的顺序是固定的,比如 out 的顺序,或者 err 的顺序,所以当我们单独使用它们其中一个的时候,就不用担心它们打架了。

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭