深度思考Java成员变量的初始化
写Java代码的时候很少去关注成员变量的声明和初始化顺序,今天借此机会抛出一些问题:语言的设计者们为什么会这样设计?比如说很常见的一个问题:abstract(抽象)类不能用final进行修饰。这个问题比较好理解:因为一个类一旦被修饰成了final,那么意味着这个类是不能被继承的,而abstract(抽象)类又不能被实例化。如果一个抽象类可以是final类型的,那么这个类又不能被继承也不能被实例化,就没有存在的意义。从语言的角度来讲一个类既然是抽象类,那么它就是为了继承,所以给它标识为final是没有意义的。语言的设计者们当然不可能让这么大的一个bug产生。对于开发者而言抽象类不能修饰final可能就是一种约定俗成的规定,并没有特殊意义。我们完全可以往前想一点:为什么这么设计?
下面我所展示的一些代码实例也同样会采用我上面的一些思考方法。有一些是一些”契约“,并没有特别的缘由,可能用别的方法也是合理的。下面的代码会讲到初始化的一些策略,从实际的执行结果中得出一些结论。
public class Test7 { static{ a = 5; } private static final int a; public static void main(String[] args){ System.out.println(a); }}代码七和代码六的不同在于使用静态化的初始化方法,并不会违背final有且仅有一次赋值这样的一个约定。
上面七段代码大概阐述了一下变量的初始化顺序。大部分结果可以通过一些已有的结论推敲出来,也方便我们进行记忆。很多人可能会问:了解这些有用吗?如果只能看到我上面所写的那七段代码,可能意义并不大,在平常的编码过程中也不太可能会去那么写,即使写错了eclipse也会很明显的把错误指出来。而我得出的结论:从语言设计者的角度来思考Java语言为什么这么设计?如果这样去思考,然后再进行深度挖掘,一定可以得出一些不一样的理解,甚至可以找出java语言的设计不好的地方。
- 11楼u01009034738分钟前
- 好
- 10楼lynnlovemin1小时前
- 顺便补充一句,代码四答案是会打印4,并且里面的System.out.println(a);也会输出,LZ没有测试过?而且理论上也不可能打印0撒,建议楼主看看jvm相关知识
- Re: luohuacanyue1小时前
- 回复lynnloveminn我肯定是测试过的,你可以去测试一下,这里直接输出静态变量a,并不能触发动态块的执行,即使你把动态块放到变量后面也不会触发。这里为什么我也没想得很清楚,虽然后面我有自己的结论,但是仅仅是根据现象得出来的,目前我的解释只能是"lazy initial和按需加载“。说的直白点就是一种规范。代码三是会输出4的,因为代码三中new了一个对象,对静态变量进行了又一次赋值。
- 9楼u0117857662小时前
- 拜读了,思想挺好的...
- Re: luohuacanyue1小时前
- 回复u011785766n思想很重要,知识积累一个重要的目标就是思考,有自己的想法。
- 8楼jiangfullll昨天 17:40
- 额,我的直观感受是,如果你会看javap的话,应该不是很难理解吧?
- Re: luohuacanyue昨天 20:36
- 回复jiangfulllln这个我看过一些字节码,有一些问题是可以解决的,比如说int a =2和int a;{a=2;}这两种方式在字节码层面是一样的,但是仍然无法解释我在代码四中的问题。
- 7楼wu00103356昨天 15:48
- 看的很糊涂啊
- Re: luohuacanyue昨天 17:24
- 回复wu00103356n确实会有点绕,建议静下心来自己演示一下!会比较有感觉。
- 6楼caodegao昨天 11:59
- 看到答案后,想想还是有点理解,如果作为编译是否正确的考试题,估计真不会看出问题的所在.基础啊基础,对你又爱又恨
- 5楼u012413257昨天 10:00
- 不是特别赞同在这一个点上纠结,但是作为java语言深度挖掘还是不错的!
- Re: luohuacanyue昨天 11:28
- 回复u012413257n目前来讲对于Java语言层面很多东西都没有想透,基本上都限于使用方面,希望是一从至内而外的一种融会贯通。
- 4楼Etoak_james昨天 09:22
- 不错 顶了nnnQQ群:294881724 java高性能 和sql优化。
- 3楼yfkiss昨天 09:21
- 很棒的思考!赞下!
- 2楼suannai0314昨天 09:13
- 您的文章已被推荐到CSDN首页,感谢您的分享。
- 1楼lynnlovemin昨天 08:19
- 很简单,java的ClassLoader会首先将static加载,所以static变量会首先执行,所以在{a=4;System.out.println(a);}不会报错,因为在执行之前用static修饰的变量已经声明引用了,而没有被static修饰的会按照顺序依次加载,因此会报错,你试着将private int a;放到最前面,结果就不会报错。
- Re: luohuacanyue昨天 08:41
- 回复lynnloveminn我知道放到前面是不会报错的,那样就得不出我想说的结论,这里我无法理解的是为什么这里可以赋值,而并不能使用?当然我在书中找到我在此文中标红的那个结论:”定义在声明之前的静态化块只能对声明变量进行赋值,并不能使用该变量“