`

全世界所有程序员都会犯的错误

 
阅读更多
当年,国际巨星成龙的「龙种」曝光,众人指责他对不起娇妻林凤娇,逼得他出面召开记
者会,向世人自白他犯了「全世界所有男人都会犯的错误」。从来没犯过这种错误的我,
也因此常常认为自己不是个男人。

虽然没犯过「全世界所有男人都会犯的错误」,但是我倒是曾经犯了「全世界所有程序员
都会犯的错误」。不管使用何种语言,全世界所有程序员都一定犯过这种错误,那就是:
太依赖编译器,却不知道编译器做了哪些事。

一般来说,越高阶的程序语言,会提供越多语法上的便利,以方便程序撰写,这就俗称为
syntacticsugar,我称其为「语法上的甜头」。虽说是甜头,但是如果你未能了解该语法
的实质内涵,很可能会未尝甜头,却吃尽苦头。

不久前,我收到一个电子邮件,读者列出下面的Java程序,向我求救。看过这个程序之后
,我确定这又是一个「全世界所有程序员都会犯的错误」。

//程序1

classSingleton{
privatestaticSingletonobj=newSingleton();
publicstaticintcounter1;
publicstaticintcounter2=0;
privateSingleton(){
counter1++;
counter2++;
}
publicstaticSingletongetInstance(){
returnobj;
}
}

//程序2
publicclassMyMain{
publicstaticvoidmain(String[]args){
Singletonobj=Singleton.getInstance();
System.out.println("obj.counter1=="+obj.counter1);
System.out.println("obj.counter2=="+obj.counter2);
}
}

执行结果是:
obj.counter1==1
obj.counter2==0

你有没有被此结果吓一跳?乍看程序代码,你很可能会认为counter1和counter2的值一定
会相等,但执行结果显然不是如此。其实,程序1被编译后的程序应该等同于下面的程序3


//程序3
classSingleton{
privatestaticSingletonobj;
publicstaticintcounter1;
publicstaticintcounter2;
static{//这就是classconstructor
//在进入此classconstructor之前,class已经被JVM
//配置好内存,所有的staticfield都会被先设定为0,
//所以此时counter1和counter2都已经是0,且singleton为null
obj=newSingleton();//问题皆由此行程序产生
//counter1不会在此被设定为0
counter2=0;//counter2再被设定一次0(其实是多此一举)
}
privateSingleton(){//这是instanceconstructor
counter1++;
counter2++;
}
publicstaticSingletongetInstance(){
returnobj;
}
}

这是因为:当class具有staticfield,且直接在宣告处透过「=...」的方式设定其值时,
编译器会自动将这些叙述依序搬到classconstructor内。同样地,当class具有instance
field,且直接在宣告处透过「=...」的方式设定其值时,编译器会自动将这些叙述依序
搬到instanceconstructor内。

此程序在classconstructor内,还未将staticfield初始化时(这时候,counter1和cou
nter2都是0),就呼叫instanceconstructor,而instanceconstructor竟然还会去更动
staticfield的值,使得counter1和counter2都变成1。然后instanceconstructor执行完
,回到classconstructor,再把counter2的值设为0(但是
counter1维持不变)。最后的结果:counter1等于1,counter2等于0。

欲改正程序1,方法有三:

-方法一:将singletonfield的宣告调到counter1与counter2field之后。
这是最好的作法。
-方法二:将counter2=0的宣告中,「=0」的部分删除。这种作法只有在希望
-方法三:将初始化的动作搬到classconstructors内,自行撰写,而不依赖
编译器产生。这是最保险的作法。

如何避免犯下「全世界所有程序员都会犯的错误」,我给各位Java程序员
的建议是:
-熟读JavaLanguageSpecification
-在有疑问时,使用J2SDK所提供的javap来反组译JavaBytecode,直接观察
编译后的结果。

下面是我用javap来反组译程序1的示范:

C:/>javap-c-classpath.Singleton

CompiledfromMyMain.java
classSingletonextendsjava.lang.Object{
publicstaticintcounter1;
publicstaticintcounter2;
publicstaticSingletongetInstance();
static{};
}

MethodSingleton()
0aload_0
1invokespecial#1<Methodjava.lang.Object()>
4getstatic#2<Fieldintcounter1>
7iconst_1
8iadd
9putstatic#2<Fieldintcounter1>
12getstatic#3<Fieldintcounter2>
15iconst_1
16iadd
17putstatic#3<Fieldintcounter2>
20return

MethodSingletongetInstance()
0getstatic#4<FieldSingletonobj>
3areturn

Methodstatic{}
0new#5<ClassSingleton>
3dup
4invokespecial#6<MethodSingleton()>
7putstatic#4<FieldSingletonobj>
10iconst_0
11putstatic#3<Fieldintcounter2>
14return

其实Java的syntacticsugar并不算多,C#的syntacticsugar才真的是无所不在,
也因此C#的初学者更容易犯了「全世界所有程序员都会犯的错误」。许多C#的书都会一边
介绍C#语法,一边介绍编译之后MSIL(.NET的中间语言,类似Java的Bytecode)的结果,
然而Java的书却鲜少这么做。

虽说是「全世界所有程序员都会犯的错误」,但是这不代表你犯了此错误之后,仍可以同
爱借钱的曹启泰一般地「抬头挺胸、理直气壮」。只要有心,其实这一类的错误仍是可以
避免的。
分享到:
评论

相关推荐

    论全世界所有程序员都会犯的错误

    论全世界所有程序员都会犯的错误

    C++程序员容易犯的十个C#错误

    C++程序员容易犯的十个C#错误 C++程序员在转换到C#时,经常会遇到一些错误。本文将讨论C++程序员最容易犯的十个错误,帮助C++程序员更好地理解C#语言和.NET Framework。 错误1:析构函数上的差异 C++程序员在使用...

    程序员不应该再犯的五大编程错误

    然而,有一些错误是不应该重复的,尤其是那些在程序员的编程生涯中容易犯的常见错误。初学者由于经验不足,往往更易陷入这些误区。但不管是不是初学者,了解并刻意避免这些错误,对于提升编程技能和代码质量是至关...

    每个程序员都会的35种小技巧

    每个程序员都会的35种小技巧,干货推荐,每个程序员都会的35个jQuery小技巧!

    程序员犯的非技术错误(Top 5)[1].doc

    最后,不愿意学习新事物是程序员容易犯下的非技术错误。技术行业正处于一个快速发展和不断变革的阶段,新工具、新技术和新框架层出不穷。程序员必须具备开放的心态,持续学习和探索,以跟上技术发展的步伐。固守旧有...

    程序员跳槽全攻略

    程序员跳槽全攻略。

    程序员最常犯的五大非技术性错误

    程序员最常犯的五大非技术性错误

    全世界程序员都在用的护眼软件——flux

    标题中的“全世界程序员都在用的护眼软件——flux”指的是f.lux,这是一款非常流行的电脑护眼软件,尤其受到全球程序员的欢迎。f.lux的设计理念是减轻长时间使用电脑屏幕对眼睛的伤害,它会根据一天中的时间自动调整...

    读书笔记:中国程序员最容易犯的100个英语口语错误.zip

    读书笔记:中国程序员最容易犯的100个英语口语错误

    程序员跳槽全攻略.pdf

    程序员跳槽全攻略是一本专注于程序员职业发展和职业规划的电子书,它提供了程序员在考虑换工作时需要考虑的诸多因素和策略。内容涉及如何评估现有工作,如何准备跳槽,如何在面试中表现出色,以及如何在新公司中快速...

    程序员专用 编程输入法

    总的来说,程序员专用的输入法如精灵输入法,是通过提供高效便捷的编码环境,帮助程序员提升工作效率,减少错误,从而更好地投入到软件开发工作中。这样的工具对于经常进行编程工作的人员来说是非常有价值的。

    Python-中国程序员容易发音错误的单词

    中国程序员容易发音错误的单词 (以美式发音为准, 非音标为字母发音)

    程序员项目交接文档

    程序员项目交接文档概要 ...程序员项目交接文档是程序员在项目交接过程中的重要文件,涵盖了项目的所有方面,包括人事管理、消息推送等模块的数据结构和关系、执行流程、功能实现等方面的详细记录。

    历年程序员考试真题

    2000-2010历年程序员考试真题,对软考程序员的一些试题总结,包含答案;程序员考试上午科目和下午科目的考试形式与考核内容已经趋于稳定,考生应紧扣考试大纲和指南,有针对性地进行学习。

    程序员必备简历模板(适用于所有程序员)

    该简历模板适用于所有程序员,包括但不限于软件开发工程师、测试工程师、前端开发工程师等。无论是有经验的程序员还是初学者,都可以使用该模板来展示自己的技能和经验。 场景目标: 该简历模板的场景目标是帮助...

    程序员简历程序员简历.pdf

    程序员简历程序员简历.pdf

Global site tag (gtag.js) - Google Analytics