|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
通过视频学习比传统的大课堂学习更适合成人化的学习规律。有人说大课堂气氛好,学习氛围浓,热闹,可以认识很多人。程序|程序员|毛病昔时,国际巨星成龙的「龙种」暴光,世人求全谴责他对不起娇妻林凤娇,逼得他出头召开记
者会,向众人自白他犯了「全球一切汉子城市犯的毛病」。历来没犯过这类毛病的我,
也因而经常以为本人不是个汉子。
固然没犯过「全球一切汉子城市犯的毛病」,可是我却是已经犯了「全球一切程序员
城市犯的毛病」。不论利用何种言语,全球一切程序员都必定犯过这类毛病,那就是:
太依附编译器,却不晓得编译器做了哪些事。
一样平常来讲,越高阶的程序言语,会供应越多语法上的便当,以便利程序撰写,这就俗称为
syntacticsugar,我称其为「语法上的长处」。虽然说是长处,可是假如你未能懂得该语法
的本色内在,极可能会何尝长处,却吃尽甜头。
不久前,我收到一个电子邮件,读者列出上面的Java程序,向我求救。看过这个程序以后
,我断定这又是一个「全球一切程序员城市犯的毛病」。
//程序1
classSingleton{privatestaticSingletonobj=newSingleton();publicstaticintcounter1;publicstaticintcounter2=0;privateSingleton(){counter1++;counter2++;}publicstaticSingletongetInstance(){returnobj;}}//程序2publicclassMyMain{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
:
//程序3classSingleton{privatestaticSingletonobj;publicstaticintcounter1;publicstaticintcounter2;static{//这就是classconstructor//在进进此classconstructor之前,class已被JVM//设置好内存,一切的staticfield城市被先设定为0,//以是此时counter1和counter2都已是0,且singleton为nullobj=newSingleton();//成绩皆由此路程序发生//counter1不会在此被设定为0counter2=0;//counter2再被设定一次0(实际上是画蛇添足)}privateSingleton(){//这是instanceconstructorcounter1++;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.SingletonCompiledfromMyMain.javaclassSingletonextendsjava.lang.Object{publicstaticintcounter1;publicstaticintcounter2;publicstaticSingletongetInstance();static{};}MethodSingleton()0aload_01invokespecial#1<Methodjava.lang.Object()>4getstatic#2<Fieldintcounter1>7iconst_18iadd9putstatic#2<Fieldintcounter1>12getstatic#3<Fieldintcounter2>15iconst_116iadd17putstatic#3<Fieldintcounter2>20returnMethodSingletongetInstance()0getstatic#4<FieldSingletonobj>3areturnMethodstatic{}0new#5<ClassSingleton>3dup4invokespecial#6<MethodSingleton()>7putstatic#4<FieldSingletonobj>10iconst_011putstatic#3<Fieldintcounter2>14return
实在Java的syntacticsugar其实不算多,C#的syntacticsugar才真的是无所不在,
也因而C#的初学者更简单犯了「全球一切程序员城市犯的毛病」。很多C#的书城市一边
先容C#语法,一边先容编译以后MSIL(.NET的两头言语,相似Java的Bytecode)的了局,
但是Java的书却鲜少这么做。
虽然说是「全球一切程序员城市犯的毛病」,可是这不代表你犯了此毛病以后,仍能够同
爱乞贷的曹启泰一样平常地「仰面挺胸、义正词严」。只需故意,实在这一类的毛病还是能够
制止的。
你对java乐观有点盲目。java的关键就是在服务器上表现优异,而且它提供了整个开发所需要的工具。应该是说,看哪天。net有没有机会赶上java。 |
|