public class Test {
static int i = 20; public Test() {
System.err.println("new");
} static {
int i = 10;
System.err.println("static");
} public static void main(String[] args) {
Test a = new Test();
System.out.println(a.i);
}
}昨天看见的一道题,我以为执行的结果是
static
10
new谁知道运行一看我很郁闷:
下面是我运行的结果:
第一次运行:
static
20
new第二次运行的结果:
static
new
20第三次:static20可以得出结论的是static 块比构造方法先执行。但是关于打印那部分不知道怎么解释......new

解决方案 »

  1.   

    i = 20是编译时刻确定的,输出的肯定是20。就输出顺序来讲,我在JCreator里运行了几次,都和你第二次运行的结果一样啊~~
      

  2.   

    确实有不同结果
    = 1 =====================
    static
    new
    20
    = 2 =====================
    20
    static
    new
    = 3 =====================
    static
    20new
    ==============================
    static 在 new之前是可以确定的
    static在类加载的时候print的
    new在构造时候print的
    至于20就不清楚了,等待高手
      

  3.   

    改成System.out.println就只有一个结果了,应该跟System.err.println有关public class Test {
    static int i = 20; public Test() {
    System.out.println("new");
    } static {
    int i = 10;
    System.out.println("static");
    } public static void main(String[] args) {
    Test a = new Test();
    System.out.println(a.i);
    }
    }
      

  4.   

    为什么我测试结果不管是System.out还是System.err都是:static new 20???
      

  5.   

    参考一下 这里
    http://fishermen.javaeye.com/blog/24025
      

  6.   

    1、在类第一次加载时候,会执行静态域(field)初始化语句和静态块(用static{}包含的部分)。 
    这里要注意: 
        a、不管静态域声明语句的实际位置在哪儿,当第一次加载类的时候都会首先对它初始化为缺省值(0,false,null等)。 
        b、即使静态域声明中使用了显式初始化语句(比如:int x=3),第一次加载类的时候也会先把它初始化为缺省值(此时x为0),然后再按照下面说的要点c来执行赋值语句(x=3)。 
        c、对于静态域的显式初始化语句和静态块,按照在类中代码出现的先后顺序执行。 
         因此,在上面的例子程序中,我们看到 
          static int s_a=1; 
          static 
          { 
             s_a=11; 
             s_b=22; 
           } 
           static int s_b=2; 
          对s_a,s_b会有不同的效果。类加载时候,s_a,s_b都被初始化为0,然后由于依照代码顺序执行了s_a=1;s_a=11;s_b=22;s_b=2;结果s_a、s_b分别变成了11和2。 2、当构造类实例时候,会先对实例域初始化为缺省值,然后执行实例块(用{}括起来的部分),然后执行构造方法。其中: 
        a、如同1中一样,如果有实例域的显式初始化语句,程序仍然是先将该域初始化为缺省值,然后按照代码在类中出现的先后顺序执行初始化语句或者实例块。如果实例块位置在初始化语句前面,即使它改变了该域的值,也会被随后执行的初始化语句改回去。 
        b、在进入构造方法后,如果构造方法第一句是使用this(...)调用另一构造方法的话,则先执行另一构造方法,然后再执行本构造方法的方法体。这种用法必须让this(...)位于第一句。 《Core java 2》书中所说的"进入构造方法后,如果第一句是调用别的构造方法,则进入别的构造方法。否则,执行实例块"的提法有问题。事实是,不管是否使用this()都会先执行实例块,再进入构造方法。另外,本程序需要在sdk1.4下编译,在sdk1.3下编译将不允许在静态块或实例块中改变位置在它们后面声明的域的值。 
      

  7.   

    static 这个方法体,其实和 构造函数 差不多,具体如下 :
    1 每个类初始化时,会先初始化它的static再执行构造方法,当static已经执行过后,该类的新的实例不会再执行static
    2 该类如果继承了某个类则父类的static会先初始化。
    3 某个类即便有static main方法,并且该类作为执行类,因此,可以得到如下顺序:
    * 1 父类static 变量/代码块 初始化(即使父类static是private的也会初始化,只会初始化一次)
    * 2 子类static 变量/代码块 初始化
    * 3 父类构造方法
    * 4 子类构造方法
    * static变量和static代码块的初始化顺序按照书写的先后顺序初始化
      

  8.   

    我想弱弱地问一下,楼主那里的static int i=20;后来静态块那里的int i=10;两个i 相同么?
      

  9.   

    不相同的一个是成员变量 一个是局部变量
       如果静态块那里的int i=10写成i=10就相同了
       至于为什么先答应20再打印new我也很纳闷
      

  10.   

    我也测试了下,结果:
    第一次:
    static
    new
    v
    第二次:
    20
    static
    new
    关于20不理解,等待高手指点。
      

  11.   

    上个打错了,SORRY
    我也测试了下,结果: 
    第一次: 
    static 
    new 
    20
    第二次: 
    20 
    static 
    new 
    关于20不理解,等待高手指点。
      

  12.   

    1、10,还是20。
      当然是20,那个“i=10”的赋值,是对一个局部变量i的操作。2、static代码块和构造的先后。
      static块是在加载类时被调用,构造是在new一个对象时被调用,当然是static先于构造。3、顺序。
      同一个流(err)输出的顺序是不会变的,所以static肯定在new之前。out和err是2个流,哪个先把数据流到指定的地方(如控制台)都有可能,和多线程差不多。所以20可能在static之前,可能在new之后,还可能在二者之间。而且因为println的换行和正文是分2次流出,所以20的前后可能还没换行就有static或new。
      

  13.   

    打印20没有疑义。只是奇怪为什么每次打印的顺序不同?我觉得第一次应该是 static new 20.后面几次的 static 可还会打印吗?
      

  14.   

    我的JDK  JRE都是1.5.0无论我怎么运行,结果只有一种
    20
    static
    new跟我想的完全不一样,我汗死…………
      

  15.   

    我改成out.println后也总是 static new 20
      

  16.   

    我的运行环境是jdk 1.6  Eclipse 3.4
      

  17.   

    而我用err.println  然后单步调试的时候
    规律也总是static new 20而执行程序时却又规律不同了两种情况我都试了很多次,不是巧合问题郁闷了
      

  18.   

    运行环境jdk1.6  eclipse3.5
      

  19.   

    有两种结果:static new 20
               static 20 new
    不过要是把system.err.println换成system.out.println就只有static new 20这一种结果。
    不太懂为什么。
      

  20.   

    郁闷那个static{}里面重新定义了一个int i = 10 OK?
    重新定义了一个局部变量而已跟原来的i根本没关系原来的i当然是20啦
      

  21.   

    System.err.println()与System.out.println()我百度了一下:
        err是需缓冲的,所以打印结果不一样可以理解
      

  22.   

    输入程序,使用IDA反编译Test.class文件就很清楚第一个问题了:  .limit stack 2
      .limit locals 1
      .line 4
        bipush 20
        putstatic src/Test.i I ;static int i=20;
      .line 11
        bipush 10
        istore_0 ; met001_slot000 {int i=10;}
      .line 12met001_8:                                      ; DATA XREF: met001_slot000i
        getstatic java/lang/System.err Ljava/io/PrintStream;
        ldc "static"
        invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V
      .line 3
        return
    met001_end:                                    ; DATA XREF: met001_slot000i
    ;met001_slot000                                ; DATA XREF: <clinit>+7w
        .var 0 is i I from met001_8 to met001_end
      .end methodstatic {statements}这种形式,我理解为声明一个包含statements的对象,所以它们都在<clinit>方法里,而构造函数是<init>,后于<clinit>运行.至于第二个输出先后的问题,由于(参考jdk源代码)
    public final static PrintStream err
    public final static PrintStream out
    它们是两个流变量
    而PrintStream中println除了无参数的那个版本外,重载的其他版本都使用了synchronized机制,所以这牵涉到java里的多线程问题.....具体细节就没继续看了.....
      

  23.   


    运行了N次 觉得这还是跟线程有关,实际的运行顺序就是: static new 20 ,之所以打印顺序不同,那是因为我们被表面现象所迷惑了,System.err跟System.out调用的都是println方法,再看看println()方法:
        public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
        }       public void println(int x) {
    synchronized (this) {
        print(x);
        newLine();
    }
        }
    原因由此可见。
    感谢prog_6103 ,本以为盖棺定论了,谢谢你的提醒。
      

  24.   

    PrintStream的synchronized方法,只是保证多线程调用同一个流时不会出现输出内容交错。在这里,就是先出static后出new,而且static和new之间必然有换行。