我在网上查了很多资料都是说:java中static变量的初始化要在static块的之前执行,并且这个网页http://blog.csdn.net/ice_kane/archive/2010/01/15/5194168.aspx给出了代码证明。但是我自己写的代码却说明static变量和static块的执行顺序取决于他们在类中的声明顺序,我的代码如下:public class StaticTest {  
static{//静态块在静态变量之前声明
a=100;
} public static int a=10; public static void main(String[] args) {
System.out.println(StaticTest.a);//这里打印出的是10,说明public static int a=10;在static块之后                  执行
    }   
}public class StaticTest {  
public static int a=10;//静态变量在静态块之前声明 static{
a=100;
} public static void main(String[] args) {
System.out.println(StaticTest.a);//这里打印出的是100,说明static块在public static int a=10之后执行
    }   
}如果按照静态变量先于static块初始化的理论,两个程序打印出来的应当都是100啊,我就不明白了
我也不知道我说清了没有  

解决方案 »

  1.   

    如果是按照顺序执行的为什么这个代码编译时会出现“非法先前引用”的错误
    public class StaticTest {  
    static{
    System.out.println(a);//出现“非法先前引用”
    }
    public static int a=10;
    public static void main(String[] args) {
    System.out.println(StaticTest.a);
        }   
    }而下面这个代码不会出现
    public class StaticTest {  
    static{
    a=20;//这个不会出现“非法先前引用”
    }
    public static int a=10;
    public static void main(String[] args) {
    System.out.println(StaticTest.a);
        }   

    真是挺奇怪的
      

  2.   

    难道只有赋值操作才可以写到前面???我的MyEclipse提示的是未定义。。public static int a;

    static {
    a = 100;
    System.out.println(a);
    }这样是没问题的
      

  3.   

    我也有这个疑问呢,我觉得2楼ticmy说的方法能够解释清楚,但是我现在还没搞懂,呵呵
      

  4.   

    用javap -c 反编译那两个类出现的东西是一样的,这个是什么意思啊?
      

  5.   

    楼主认真的看下那篇文章吧。
    http://blog.csdn.net/ice_kane/archive/2010/01/15/5194168.aspx那么对于静态变量和静态初始化块之间、变量和初始化块之间的先后顺序又是怎样呢?是否静态变量总是先于静态初始化块,变量总是先于初始化块就被初始化了呢?实际上这取决于它们在类中出现的先后顺序。
      

  6.   


    public class StaticTest {  
        static{//静态块在静态变量之前声明
            a=100;
        }
        public static int a=10;    public static void main(String[] args) {
            System.out.println(StaticTest.a);//这里打印出的是10,说明public static int a=10;在static块之后 执行
        }  
    }一个类在你用之前有“装载,链接,初始化”这么几个阶段,链接又有“验证,准备,解析”这三个阶段。
      装载就是把2进制的class文件加载到JVM。
      链接就是分配内存,将符号引用解析为直接引用还有给变量赋默认值。(静态变量[类变量]就是在这个阶段创建的)
      初始化就是执行初始化语句和初始化块。初始化顺序为(见The Java Language Specification§12.4.2):
        <fieldset>
        9. Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they
    were a single block, except that final class variables and fields of interfaces
    whose values are compile-time constants are initialized first (§8.3.2.1, §9.3.1,
    §13.4.9).
        </fieldset>    
    好,再看你的代码:
        public static int a
      a这个变量是在准备阶段创建的(链接的第二个阶段),创建玩并给了默认值0,int变量的默认值为0.然后到类的初始化阶段按照文本中出现的先后顺序进行初始化。先执行static块中的,初始化为100,然后再执行你声明时的显示初始化 a=10,最后a的值为10.所以在main中打印的结果就位10了。再看你的第二个疑问,为什么会有“非法先前引用”的问题。先看The Java Language Specification§8.3.2.3的描述:
    <fieldSet>
      The declaration of a member needs to appear textually before it is used only if
    the member is an instance (respectively static) field of a class or interface C and
    all of the following conditions hold:
    • The usage occurs in an instance (respectively static) variable initializer of C
    or in an instance (respectively static) initializer of C.
    • The usage is not on the left hand side of an assignment.
    • The usage is via a simple name.
    • C is the innermost class or interface enclosing the usage.
    </fieldset>
    就是说 如果以下四种情况全部满足,那么类C的成员要在用之前声明:(大概翻译下,不是很准确)
     1·在(实例/静态)变量初始化器中或者(实例/静态)初始化器中使用
     2·使用时不在赋值语句的左边
     3·通过简单名词使用
     4·C是一个最内部的类但是在外部的类中使用
    public class StaticTest {  
        static{
            System.out.println(a);//static块中使用a符合上述情况,要在使用前声明,所以出现了一个error。
                                 // 如果改为System.out.println(StaticTest.a)就不会报错了。(不符合第3点,没使用简单名称a,而用了StaticTest.a)
        }
        public static int a=10;
        public static void main(String[] args) {
            System.out.println(StaticTest.a);
        }  
    }public class StaticTest {  
        static{
            a=20;//这个a在赋值语句的左边,不符合第2点。所以是可以的。
        }
        public static int a=10;
        public static void main(String[] args) {
            System.out.println(StaticTest.a);
        }  
    }  
      

  7.   

    public class StaticTest {   
    static{
    System.out.println(a);//出现“非法先前引用”
    }
    public static int a=10;
    public static void main(String[] args) {
    System.out.println(StaticTest.a);
      }   
    }
    你这边a不是还没有声明,就直接使用它的引用了,当然是非法引用了
      

  8.   

    恩,是我没认真看完那篇文章,现在明白了,但是我还有疑问,为什么
    public class StaticTest {   
    static{
    a=20;//这个不会出现“非法先前引用”
    System.out.println(a);//这里为什么会出现“非法先前引用”?}
    public static int a=10;
    public static void main(String[] args) {
    System.out.println(StaticTest.a);
      }   

    a的声明在静态块之后,但是为什么静态块中a=20;不会出现“非法向前引用”,而System.out.println(a);会出现“非法向前引用”?
      

  9.   


    public class StaticTest {

    static {
    a = 100;
    } public static int a;

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

    }
    }这个运行结果是100,而不是0,说明顺序是这样的,首先创建static的字段,并初始化为0,然后按顺序执行static的赋值语句
      

  10.   

    恩,赋值为0是全局变量的默认值,之后执行static块,最后就不执行public static int a;的默认赋值了