`
touchmm
  • 浏览: 1003808 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Static变量和实例变量的初始化顺序问题

阅读更多

问题重现

让我们先来看一下以下的程序:

 1  public   class  StaticInitSequence {
 2        // -------------------Static fields-------------------
 3        private   static   int  staticIntVar  =   10 ;
 4        private   static   int  staticComputeIntVar  =  ( int )(Math.random()  *   10 );
 5        private   static  String staticStrVar  =   " Static field init(before) " ;
 6        private   static  Object staticRefVar  =   new  Object();
 7      
 8        static  {
 9          staticIntVar  =   20 ;
10          staticStrVar  =   " Static block init(before) " ;
11          staticAfterIntVar  =   40 ;
12          staticAfterStrVar  =   " Static block init(after) " ;
13       }
14      
15        private   static   int  staticAfterIntVar  =   30 ;
16        private   static  String staticAfterStrVar  =   " Static field init(after) " ;
17      
18        // ---------------------Instance fields----------------
19        private   int  fieldIntVar  =   100 ;
20        private   int  fieldComputeIntVar  =  ( int )(Math.random()  *   100 );
21        private  String fieldStrVar  =   " Instance field init(before) " ;
22      
23        public  StaticInitSequence() {
24          fieldIntVar  =   200 ;
25          fieldStrVar  =   " Constructor field init(before) " ;
26         
27          fieldAfterIntVar  =   400 ;
28          fieldAfterStrVar  =   " Constructor field init(after) " ;
29       }
30      
31        private   int  fieldAfterIntVar  =   300 ;
32        private  String fieldAfterStrVar  =   " Instance field init(after) " ;
33      
34        public   void  print() {
35          System.out.println( " ----------------Static Fields------------ " );
36          System.out.println( " staticIntVar:  "   +  staticIntVar);
37          System.out.println( " staticComputeIntVar:  "   +  staticComputeIntVar);
38          System.out.println( " staticStrVar:  "   +  staticStrVar);
39          System.out.println( " staticRefVar:  "   +  staticRefVar);
40          System.out.println( " staticAfterIntVar:  "   +  staticAfterIntVar);
41          System.out.println( " staticAfterStrVar:  "   +  staticAfterStrVar);
42         
43          System.out.println( " -----------------Instance Fields--------- " );
44          System.out.println( " fieldIntVar :  "   +  fieldIntVar);
45          System.out.println( " fieldComputeIntVar :  "   +  fieldComputeIntVar);
46          System.out.println( " fieldStrVar :  "   +  fieldStrVar);
47          System.out.println( " fieldAfterIntVar :  "   +  fieldAfterIntVar);
48          System.out.println( " fieldAfterStrVar :  "   +  fieldAfterStrVar);
49       }
50   }

如果我们调用以上类的 print() 方法( new StaticInitSequence().print() ),会有什么样的结果呢?

我自认为,直接对一个字段初始化是编译器提供支持的一种编程方式,这种编程方式可以提高代码的可读性,因为用户可以直接知道一个字段的初始值,而不用到构造函数或者静态语句块里面去找。在 Java 中,实际编译后的二进制文件中,所有的字段初始化语句都放在了初始化函数中(类(静态)初始化函数( <clinit> )或者实例初始化(构造函数 /<init> )函数)。因此在我的逻辑思维中,在源代码中,初始化函数应该可以改变字段初始化中的值,这样还就可以在字段初始化中提供一个初始值,而在初始化函数中根据需要改变它。然而另我感到意外的是 Java 中只有实例初始化机制是这样实现的,而静态字段初始化中没有实现这种机制(在 C# 中不管实例初始化和静态初始化都实现了这种机制),静态字段初始化的顺序是完全根据源代码中定义顺序来初始化的;从耦合的角度,这就是一个顺序耦合的典型。不知道为什么 Java 要这样实现,是否它有其他方面的问题的考虑?亦或是 Java 设计者或者 Java 编译器设计者的一个失误?不管怎么样,用 sun javac 编译出来的以上程序的运行结果如下:

---------------- Static Fields ------------
staticIntVar: 
20
staticComputeIntVar: 
7
staticStrVar: Static block init(before)
staticRefVar: java.lang.Object@14318bb
staticAfterIntVar: 
30
staticAfterStrVar: Static field init(after)
----------------- Instance Fields ---------
fieldIntVar : 
200
fieldComputeIntVar : 
8
fieldStrVar : Constructor field init(before)
fieldAfterIntVar : 
400
fieldAfterStrVar : Constructor field init(after)

 

问题解释:

从以上程序生成的二进制代码就可以很好的解释以上的结果:

< clinit > :
   
// staticIntVar = 10
      0  bipush  10
     
2  putstatic org.levin.insidejvm.miscs.staticinit.StaticInitSequence.staticIntVar :  int  [ 22 ]
      
//  staticComputeIntVar = (int)(Math.random() * 10)
      5  invokestatic java.lang.Math.random() :  double  [ 24 ]
     
8  ldc2_w  < Double  10.0 >  [ 30 ]
    
11  dmul
    
12  d2i
    
13  putstatic org.levin.insidejvm.miscs.staticinit.StaticInitSequence.staticComputeIntVar :  int  [ 32 ]
    
// staticStrVar = “Static field init(before)”
     16  ldc  < String  " Static field init(before) " >  [ 34 ]
    
18  putstatic org.levin.insidejvm.miscs.staticinit.StaticInitSequence.staticStrVar : java.lang.String [ 36 ]
    
// staticRefVar = new Object();
     21   new  java.lang.Object [ 3 ]
    
24  dup
    
25  invokespecial java.lang.Object() [ 38 ]
    
28  putstatic org.levin.insidejvm.miscs.staticinit.StaticInitSequence.staticRefVar : java.lang.Object [ 41 ]
    
// staticIntVar = 20
     31  bipush  20
    
33  putstatic org.levin.insidejvm.miscs.staticinit.StaticInitSequence.staticIntVar :  int  [ 22 ]
    
// staticStrVar = “Static block init(before)”
     36  ldc  < String  " Static block init(before) " >  [ 43 ]  
    
38  putstatic org.levin.insidejvm.miscs.staticinit.StaticInitSequence.staticStrVar : java.lang.String [ 36 ]
    
// staticAfterIntVar = 40
    </
2
1
分享到:
评论

相关推荐

    java 静态非静态 字段方法 子类父类构造_初始化顺序!

    java 静态_非静态 字段_方法_代码块 子类父类构造_初始化顺序! 三个class 让你清清楚楚 第一个class java代码如下: package initialOrder; class Parent { // 静态变量 public static String p_StaticField...

    关于C++中构造函数初始化成员列表的总结

     初始化列表的初始化顺序是依据类成员变量定义的顺序来决定的。 3.关于static const是否应该在初始化成员列表中初始化?  static const为全局静态常量,全局的意思是该变量属于整个类而非某个类实例,所以不能再...

    【Java高频面试题】–类的初始化过程以及实例的初始化过程

    要创建一个类的实例,必须加载和初始化该类。 main()方法所在的类,会被优先加载并初始化 子类初始化前,会先加载并初始化它的父类 初始化一个类,其实质上就是执行了()方法 ()方法包含了,静态变量显式赋值代码以及...

    static 用法

    2. static局部变量在所处模块在初次运行时进行初始化工作, 且只操作一次 3. 对于局部静态变量, 如果不赋初值, 编译期会自动赋初值0或空字符, 而auto类型的初值是不确定的. (对于C++中的class对象例外, class的对象...

    Java 基础核心总结 +经典算法大全.rar

    类的初始化 成员初始化 构造器初始化初始化顺序 数组初始化 对象的销毁 对象作用域 this 和 super 访问控制权限继承 多态组合代理 向上转型static final 接口和抽象类接口 抽象类异常 认 识 Exception 什么是 ...

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar

    7.1.2 结构体类型变量的定义方法及其初始化 7.1.3 结构体变量的引用 7.1.4 结构体数组 7.1.5 指向结构体变量的指针 7.1.6 结构体类型数据作为函数参数 *7.1.7 动态分配和撤销内存的运算符new和delete 7.2 共用体 ...

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar )

    7.1.2 结构体类型变量的定义方法及其初始化 7.1.3 结构体变量的引用 7.1.4 结构体数组 7.1.5 指向结构体变量的指针 7.1.6 结构体类型数据作为函数参数 *7.1.7 动态分配和撤销内存的运算符new和delete 7.2 共用体 ...

    突破程序员基本功的16课.part2

    2.1.2 实例变量的初始化时机 2.1.3 类变量的初始化时机 2.2 父类构造器 2.2.1 隐式调用和显式调用 2.2.2 访问子类对象的实例变量 2.2.3 调用被子类重写的方法 2.3 父子实例的内存控制 2.3.1 继承成员变量和...

    QUALCOMM平台BUIW开发文档

     如何把CheckBox和Static控件捆绑一起 75  引用计数问题。 75  认识引用计数 75  为什么这么强调引用计数 75  哪些操作增加了引用计数 76  哪些窗口减少了引用计数 79  替换控件默认函数 81  如何让...

    Java 语言基础 —— 非常符合中国人习惯的Java基础教程手册

    的对象实际上是由若干个实例变量和实例方法组成的。当你创建出一个类的实例时,系统将 为实例变量指定内存,然后你就可以利用实例方法去做某些事情。 2.2.5 继承 继承是指建立子类的能力。子类继承了父亲的...

    Think in ActionScript 3.0Ⅰ Ⅱ Ⅲ汇总

    4.6 初始化顺序 4.7 静态属性与方法 4.7.1 static的概念 4.7.2 TestStatic.as —— static 属于这个类,不属于该类实例 4.7.4 单例模式(Singleton Pattern) 5. 多态(Polymorphism) 5.1 多态的概念 5.2 多态存在...

    Linux C程序设计大全

    3.5.3 static变量的作用——实现封装和模块化设计 3.6 编写多文件的程序——链接的作用 3.6.1 链接多个文件 3.6.2 链接时符号解析规则 3.6.3 链接规则的应用 3.7 可变参数 3.7.1 可变参数的概念 3.7.2 实现一个简单...

    C++ Primer中文版(第5版)李普曼 等著 pdf 1/3

     3.2.1 定义和初始化string对象 76  3.2.2 string对象上的操作 77  3.2.3 处理string对象中的字符 81  3.3 标准库类型vector 86  3.3.1 定义和初始化vector对象 87  3.3.2 向vector对象中添加元素 90  3.3.3 ...

    C++编程思想习题

    16.4.1“最晚辈派生”类和虚基初始化 16.4.2使用缺省构造函数向虚基“警告” 16.5开销 16.6向上映射 16.7避免MI 16.8修复接口 16.9小结 16.10练习 第17章 异常处理 17.1C语言的出错处理 17.2抛出异常 17.3异常捕获 ...

    C++Primer(第5版 )中文版(美)李普曼等著.part2.rar

     3.2.1 定义和初始化string对象 76  3.2.2 string对象上的操作 77  3.2.3 处理string对象中的字符 81  3.3 标准库类型vector 86  3.3.1 定义和初始化vector对象 87  3.3.2 向vector对象中添加元素 90  3.3.3 ...

    《你必须知道的495个C语言问题》

    书中列出了C用户经常问的400多个经典问题,涵盖了初始化、数组、指针、字符串、内存分配、库函数、C预处理器等各个方面的主题,并分别给出了解答,而且结合代码示例阐明要点。 《你必须知道的495个C语言问题》结构...

    Java入门教程(微学苑)-part1

    4.10 Java static关键字以及Java静态变量和静态方法 72 4.11 static 的内存分配 73 4.12 静态方法 74 4.13 静态初始器(静态块) 75 4.14 静态导入 75 4.15 Java final关键字:阻止继承和多态 76 4.16 类与类之间的...

    C++ Primer第四版【中文高清扫描版】.pdf

    2.3.4 变量初始化规则 44 2.3.5 声明和定义 45 2.3.6 名字的作用域 46 2.3.7 在变量使用处定义变量 48 2.4 const限定符 49 2.5 引用 50 2.6 typedef名字 53 2.7 枚举 53 2.8 类类型 54 2.9 编写自己的头文件 57 ...

Global site tag (gtag.js) - Google Analytics