掌握JAVE編程的流程控制_第1頁
掌握JAVE編程的流程控制_第2頁
掌握JAVE編程的流程控制_第3頁
掌握JAVE編程的流程控制_第4頁
掌握JAVE編程的流程控制_第5頁
已閱讀5頁,還剩81頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第3章控制程序流程

“就象任何有感知的生物同樣,程序必須能操縱自己的世界,在執行過程中作出判斷與選擇J

在Java里,我們運用運算符操縱對象和數據,并用執行控制語句作出選擇。Java是建立在

C++基礎.上的,因此對C和C++程序員來說,對Java這方面的大多數語句和運算符都應是非

常熟悉R勺。當然,Java也進行了自己的某些改善與簡化工作。

3.1使用Java運算符

運算符以一種或多種自變品為基礎,可生成一種新值。白變量采用與原始措施調用不一樣日勺

一種形式,但效果是相似內。根據此前寫程序口勺經驗,運算符的常規概念應當不難理解。

加號(+)、減號和負號(-)、乘號(*)、除號(/)以及等號(=)日勺使用方法與其他所有編

程語言都是類似日勺。

所有運算符都能根據自己內運算對.象生成一種值。除此以外,一種運算符可變化運算對象日勺

值,這叫作“副作用"(SideEffect)。運算符最常見日勺用途就是修改自己日勺運算對象,從而

產生副作用。但要注意生成時值亦可由沒有副作用日勺運算符生成。

幾乎所有運算符都只能操作“主類型"(Primitives)。唯一的例外是“="、"=="和"!=”

它們能操作所有對象(也是對象易令人混淆日勺一-種地方)。除此以外,String類支持“+”和

3.1.1優先級

運算符的優先級決定了存在多種運算符時一種體現式各部分的計算次序。Java對計算次序作

出了尤其的規定。其中,最簡樸的規則就是乘法和除法在加法和減法之前完畢。程序員常常

都會忘掉其他優先級規則,因此應當用括號明確規定計算次序。例如:

A=X+Y-2/2+Z;

為上述體現式加上括號后,就有了一種不一樣的含義。

A=X+(Y-2)/(2+Z);

3.1.2賦值

賦值是用等號運算符(二)進行的。它的意思是“獲得右邊的值,把它復制到左邊”。右邊的

值可以是任何常數、變量或者體現式,只要能產生一種值就行。但左邊H勺值必須是一種明確

的、已命名的變量。也就是說,它必須有一種物理性的空間來保留右邊的值。舉個例子來說,

可將一種常數賦給一種變量(A=4;),但不可將任何東西賦給一種常數(例如不能4:A)。

對主數據類型H勺賦值是非常直接”勺。由于.主類型容納了實際的值,并且并非指向一種對象”勺

句柄,因此在為其賦值的時候,可未來自一種地方口勺內容復制到另一種地方。例如,假設為

主類型使用“A二B",那么B處的內容就復制到Ao若接著又修改了A,那么B主線不會受這種

修改的影響。作為一名程序員,這應成為自己的常識。

但在為對象“賦值”的時候,狀況卻發生了變化。對一種對象進行操作時:我們真正操作H勺

是它的句柄。因此倘若“從一種對象到另一種對象”賦值,實際就是將句柄從一種地方復制

到另?種地方。這意味著假若為對象使用“C=D”,那么C和D最終都會指向最初只有D才指

向的那個對象。下面這個例子將向大家闡示這一點。

這里有某些題外話。在背面,大家在代碼示例里看到的第一種語句將是“package03”使用

的“package”語句,它代表本書第3章。本書每?章的箕一種代碼清單都會包括象這樣的J■

種“package”(封裝、打包、包裹)語句,它的作用是為那一章剩余的代碼建立章節編號。

在第17章,大家會看到第3章的所有代碼清單(除那些有不一樣封裝名稱的以外)都會自動

置入一種名為c03的子目錄里:第4章的代碼置入c04:以此類推。所有這些都是通過第17

章展示的CodePackage,java程序實現的;“封裝”口勺基本概念會在第5章進行詳盡的解釋。

就目前來說,大家只需記住象"package03”這樣的形式只是用于為某一章的代碼清單建立

對應的子目錄。

為運行程序,必須保證在classpath里包括了我們安裝本書源碼文獻的根目錄(那個目錄里

包括了c02,c03c,c04等等子目錄

對于Java后續的版本(1.1.4和更高版本),假如您於Imain。用package語句封裝到一種文

獻里,那么必須在程序名前面指定完整的包裹名稱,否則不能運行程序。在這種狀況下,命

令行是:

javac03.Assignment

運行位于一種“包裹”里囪程序時,隨時都要注意這方面的問題。

下面是例子:

//:Assignment,java

//Assignmentwithobjectsisabittricky

packagec03;

classNumber{

inti;

)

publicclassAssignment(

publicstaticvoidm£in(String[]args){

Numbernl=newNumber();

Numbern2=newNumber();

nl.i=9;

n2.i=47;

System,out.printin(^1:nl.i:"+nl.i+

”,n2.i:+n2.i);

nl=n2;

System,out.printinC2:nl.i:〃+nl.i+

”,n2.i:+n2.i);

nl.i=27;

System.out.printin(^3:nl.i:"+nl.i+

〃,n2.i:"+n2.i);

)

}〃/廣

Number類非常簡樸,它的兩個實例(nl和n2)是在main。里創立日勺。每個Number中歐Ji

值都賦予了一種不一樣的值。隨即,將n2賦給nl,并且nl發生變化。在許多程序設計語言

中,我們都但愿nl和n2任何時候都互相獨立。但由于我們已賦予了一種句柄,所如下面才

是真實的輸出:

1:nl.i:9,n2.i:47

2:nl.i:47,n2.i:47

3:nl.i:27,n2.i:27

看來變化nl的同步也變化了n2!這是由于無論nl還是n2都包括了相似口勺句柄,它指向相

似的對象(最初的句柄位字nl內部,指向容納了值9的一種對象。在賦值過程中,那個句柄

實際已經丟失;它的對象會由“垃圾搜集器”自動清除)。

這種特殊的現象一般也叫作“別名”,是Java操作對象的一種基本方式。但假若不樂意在這

種狀況下出現別名,又該怎么操作呢?可放棄賦值,并寫入下述代碼:

nl.i=n2.i;

這樣便可保留兩個獨立的對象,而不是將nl和r)2綁定到相似的對象。但您很快就會意識到,

這樣做會使對象內部的字段處剪發生混亂,并與原則的面向對象設計?準則相悖。由于這并非

一種簡樸的話題,因此留待第12章詳細論述,那一章是專門討論別名的。其時,大家也會注

意到對象"勺賦值會產生某些令人震驚的效果。

1.措施調用中的別名處理

將一種對象傳遞到措施內部時,也會產生別名現象。

//:PassObject.java

//Passingobjectstomethodscanbeabittricky

classLetter{

charc;

)

publicclassPassObject(

staticvoidf(Lettery){

y.c='z';

)

publicstaticvoidmein(String[]args){

Letterx=newLetter();

x.c='a';

System.out.printlnf^l:x.c:+x.c);

f(x);

System,out.printinC2:x.c:+x.c);

)

}〃/廣

在許多程序設計語言中,f()措施表面上似乎要在措施H勺作用域內制作自己H勺自變量Lottery

時一種副本。但同樣地,實際傳遞的是一種句柄。所如F面這個程序行:

y.c='z';

實際變化的I是f()之外的對象。輸出成果如下:

1:x.c:a

2:x.c:z

別名和它的對策是非常復雜的一種問題。盡管必須等至第12章才可獲得所有答案,但從目前

開始就應加以重視,以便提早發現它的缺陷。

3.1.3算術運算符

Java的基本算術運算符與其他大多數程序設計語言是相似的。其中包括加號(+)、減號(-)、

除號(/)、乘號(*)以及模數(%,從整數除法中獲得余數)。整數除法會直接砍掉小數,而

不是進位。

Java也用一種簡寫形式進行運算,并同步進行賦值操作。這是由等號前的一種運算符標識的J,

并且對于語言中的所有運算符都是固定依J。例如,為了將4加到變量x,并將成果賦給x,可

用:x+=4o

下面這個例子展示了算術運算符H勺多種使用方法:

//:MathOps.java

//Demonstratesthemathematicaloperators

importjava,util.*;

publicclassMathOps{

//Createashorthandtosavetyping:

staticvoidprt(Strings){

System,out.println(s);

)

//shorthandtoprintastringandanint:

staticvoidpint(Strings,inti){

prt(s+“="+i);

)

//shorthandtoprintastringandafloat:

staticvoidpFlt(Strings,floatf){

prt(s+〃="+f);

)

publicstaticvoidmsin(String[]args){

//Createarandomnumbergenerator,

//seedswithcurrenttimebydefault:

Randomrand=newFandom();

inti,j,k;

//,%'limitsmaximumvalueto99:

j=rand.nextlnt()%100;

k=rand.nextlnt0%100;

j);k);

i=j+k;pint("j+k”,i);

i=j-k;pint(“j-k〃,i);

i=k/j;plnl("k/j〃,i);

i=k*j;plntCk*j”,i);

i=k%j;pint("k%j",i);

j%=k;plnt(〃j%=k”,j);

//Floating-pointnumbertests:

floatu,v,w;//appliestodoubles,too

v=rand.nextFloat();

w=rand.nextFloat();

pFltCV,v);pFltCV;w);

u=v+w;pFlt("v+w”,u);

u=v-w;pFlt(“v-w〃,u);

u=v*w;pFlt("v*w",u);

u=v/w;pFlt(〃v/w〃,u);

//thefollowingalsoworksfor

//char,byte,short,int,long,

//anddouble:

u+=v;pFltC*u+=v”,u);

u-=v;pFltCu-=v〃,u);

u*=v;pFltC/u*=v〃,u);

u/=v;pFlt("u/=v",u);

)

)〃/廣

我們注意到日勺第?件事情就是用于打印(顯示)的某些快捷措施:prt()措施打印?種String;

plntO先打印一種String.再打印一種int;而pFlt()先打印一種String,再打印一種float。

當然,它們最終都要用System,out.printin0結尾。

為生成數字,程序首先會創立?種Random(隨機)對象。由于自變量是在創立過程中傳遞時,

因此Java將目前時間作為一種“種子值”,由隨機數生成器運用。通過Random對象,程序可

生成許多不一樣類型的隨機數字。做法很簡樸,只需調用不一樣的措施即可:nextIntO,

nextLongO,nextFloat()或者nextDoubleOo

若隨同隨機數生成器的成果使用,模數運算符讖)可將成果限制到運算對象減1U勺上限(本

例是99)之下。

1.一元加、減運算符

一元減號(-)和一元加號(+)與二元加號和減號都是相似的運算符。根據體現式的書寫形

式,編譯器會自動判斷使用哪一種。例如下述語句:

x=-a;

它的含義是顯然日勺。編譯器能對日勺識別下述語句:

x=a*-b;

但讀者會被搞糊涂,因此最佳更明確地寫成:

x=a*(-b);

一元減號得到日勺運算對象內負值。一元加號的含義與一元減號相反,雖然它實際并不做任何

事情。

3.1.4自動遞增和遞減

和C類似,Java提供了豐富日勺快捷運算方式。這些快捷運算可使代碼更清爽,更易錄入,也

更易讀者辨讀。

兩種很不錯的快捷運算方式是遞增和遞減運算符(常稱作“自動遞增”和“自動遞減”運算

符)。其中,遞減運算符是“一”,意為“減少一種單位”;遞增運算符是“++”,意為“增長

一種單位”。舉個例子來說,假設A是一種int(整數)值,則體現式++A就等價于(A=A+

Do遞增和遞減運算符成果生成U勺是變量的值。

對每種類型口勺運算符,均有兩個版本可供選用;一般將其稱為“前綴版”和“后綴版“前

遞增”表達++運算符位于變量或體現式的前面;而“后遞增”表達++運算符位于變量或體現

式的背面。類似地,“前遞減”怠味著一運算符位于變量或體現式H勺前面:而“后遞減”意味

著一運算符位于變量或體現式的背面。對于前遞增和前遞減(如++A或一A),會先執行運算,

再生成值。而對于后遞增和后遞減(如A++或A--),會先生成值,再執行運算。下面是一種

例子:

//:Autolnc.java

//Demonstratesthe++and-operators

publicclassAutolnc{

publicstaticvoidmain(String[Jargs){

inti=1;

prt(*i:"+i);

prt("++i:〃+++i);//Pre-increment

prl(〃i++:"+i++);//Post-increment

prt('i:〃+i);

prt(*-i:"+-i);//Pre-decrement

prt("i-:"+i-);//Post-decrement

prt("i:"+i);

staticvoidprt(Strings){

System.out.println(s);

}///:''

該程序的輸出如下:

i:1

++i:2

i++:2

i:3

—i:2

i—:2

i:1

從中可以看到,對于前綴形式,我們在執行完運算后才得到值。但對于后綴形式,則是在運

算執行之前就得到值。它們是唯一具有“副作用”的運算符(除那些波及賦值的以外)。也就

是說,它們會變化運算對象,而不僅僅是使用自己日勺值。

遞增運算符正是對“C++”這個名字的一種解釋,暗示著“超載C日勺一步”。在初期附一次Java

演講中,BillJoy(始創人之一)聲稱“Java=C++—“(C加加減減),意味著Java已清除了

C++某些沒來由折磨人日勺地方,形成?種更精簡的語言。正如大家會在這本書中學到的那樣,

Java的許多地方都得到了簡化,因此Java的學習比C++更輕易。

3.1.5關系運算符

關系運算符生成口勺是一種“布爾”(Boolean)成果。它們評價的是運算對象值之間的關系。

若關系是真實日勺,關系體現式會生成true(真);若關系不真實,則生成false(假)。關系

運算符包括不不小于(<)、不小于(>)、不不小于或等于(<=)、不小于或等于(>=)、等于

(==)以及不等于(!=)。等于和不等于合用于所有內建口勺數據類型,但其他比較不合用于

boolean類型。

1.檢查對象與否相等

關系運算符「和!二也合川于所有對象,但它們的含義一般會使初涉Java領域的人找不到北。

下面是一種例子:

//:Equiva1ence.java

publicclassEquivalence{

publicstaticvoidm&in(String[]args){

Integernl=newInteger(47);

Integern2=newInteger(47);

System.out.printin(nl==n2);

System.out.println(nl!=n2);

)

}〃/廣

其中,體現式System.out.println(nl==n2)可打印出內部的|布爾比較成果。一般人都會認

為輸出成果肯定先是true,再是false,由于兩個Integer對象都是相似口勺。但盡管對象的

內容相似,句柄卻是不一樣的,而==和!=比較的恰好就是對象句柄。因此輸出成果實際上先

是false,再是true。這自然會使第一次接觸的人感到驚奇。

若想對比兩個對象的實際內容與否相似,又該怎樣操作呢?此時,必須使用所有對象給合用

的特殊措施equals。。但這個措施不合用于“主類型”,那些類型直接使用==和!=即可。下

面舉例闡明怎樣使用:

//:EqualsMethod.java

publicclassEqualsMethod{

publicstaticvoidmain(String[]args){

Integernl=newIr.teger(47);

Integern2=newIr.teger(47);

System,out.println(nl.equals(n2));

)

)///:

正如我們估計日勺那樣,此時得到的成果是true。但事情并未到此結束!假設您創立了自己日勺

類,就象下面這樣:

//:EqualsMethod2.jciv<i

classValue(

inti;

}

publicclassEqualsMetlud2{

publicstaticvoidmain(String[Jargs){

Valuevl=newValue();

Valuev2=newValceO;

vi.i=v2.i=10();

System,out.println(vl.equals(v2));

)

}〃/廣

此時的成果又變回了false!這是由于equals。口勺默認行為是比較句柄。因此除非在自己口勺

新類中變化了equals。,否則不也許體現出我們但愿的行為。不幸的是,要到第7章才會學

習怎樣變化行為。但要注意equals。的這種行為方式同步或許可以防止某些“劫難”性的事

件。

大多數Java類庫都實現了equals。,因此它實際比較的是對象的內容,而非它們的句柄。

3.1.6邏輯運算符

邏輯運算符AND(&&)、OR(||)以及N()T(!)能生成一種布爾值(true或false)一一以自

變量用J邏輯關系為基礎。下面這個例子向大家展示了怎樣使用關系和邏輯運算符。

//:Bool,java

//Relationalandlogicaloperators

importjava,util.*;

publicclassBool{

publicstaticvoidmain(String[Jargs){

Randomrand=newRandom();

inti=rand.nextlr.t()%100;

intj=rand,nextIr.t()%100;

prtCi="+i);

prtfj=〃+j);

prt("i>jis”+(i>j));

prt(*i<jis*+(i<j));

prt("i〉=jis"+(i>=j));

prtCi<=jis'+(i<=j));

prtCi==jis'+(i==j));

prtCi!=jis'+(i!=j));

//Treatinganintasabooleanis

//notlegalJava

//!&&jis"+(i&&j));

//!prt("i||jis"+(i||j));

//!prt("!iis"+!i);

prt(i<10)&&(j<10)is”

+((i<10)&&(j<10)));

prt("(i<10)||(j<10)is”

+((i<10)||(j<10)));

)

staticvoidprt(Strings)(

System,out.println(s);

)

)〃/廣

只可將AND,OR或NOT應用于布爾值。與在C及C++中不一樣,不可將一種非布爾值當作布

爾值在邏輯體現式中使用。若這樣做,就會發現嘗試失敗,并用一種“〃!”標出。然而,后

續的體現式運用關系比較生成布爾值,然后對成果進行邏輯運算。

輸出列表看起來象下面這個樣子:

i=85

j=4

i>jistrue

i<jisfalse

i>=jistrue

i<=jisfalse

i==jisfalse

i!=jistrue

(i<10)&&(j<10)isfalse

(i<10)||(j<10)istrue

注意若在估計為String值日勺地方使用,布爾值會自動轉換成合適日勺文本形式。

在上述程序中,可將對int的定義替代成除boolean以外口勺其他任何主數據類型。但要注意,

對浮點數字H勺比較是非常嚴格H勺。雖然一種數字僅在小數部分與另一種數字存在極微小日勺差

異,仍然認為它們是“不相等”口勺。雖然一種數字只比零大一點點(例如2不停地開平方根),

它仍然屬于“非零”值。

1.短路

操作邏輯運算符時,我們會碰到一種名為“短路”口勺狀況。這意味著只有明確得出整個體現

式真或假口勺結論,才會對體現式進行邏輯求值。因此,一種邏輯體現式FI勺所有部分均有也許

不進行求值:

//:ShortCircuit.java

//Demonstratesshort-circuitingbehavior

//withlogicaloperators.

publicclassShortCirctit{

staticbooleantest1tintval)

System,out.printIn("test1(“+val+")〃);

System.out.printin(/'result:+(val<1));

returnval<1;

)

staticbooleantest2(intval)

System.out.printin(,ztest2(,zval+”)〃);

System.out.printIn(/'result:+(val<2));

returnval<2;

)

staticbooleantest3(intval)

System,out.printin("test3(“val+")〃);

System.out.printin(''result:+(val<3));

returnval<3;

)

publicstaticvoidm&in(String[]args){

if(testl(0)&&test2(2)&&test3(2))

System.out.printin(''expressionistrue");

else

System,out.printin("'expressionisfalse");

)

}〃/廣

每次測試都會比較自變量,并返回真或假。它不會顯示與準備調用什么有關的資料。測試在

下面這個體現式中進行:

if(testl(0))&&test2(2)&&test3(2))

很自然地,你也許認為所有這三個測試都會得以執行。但但愿輸出成果不至于使你大吃一驚:

if(test1(0)&&test2(2)&&test3(2))

第一種測試生成一種true成果,因此體現式求值會繼續下去。然而,第二個測試產生了一種

「alse成果。由于這意味著整個體現式肯定為「alse,所認為何還要繼續剩余R勺體現式呢?這

樣做只會徒勞無益。實際上,“短路”一詞的由來正種因于此。假如一種邏輯體現式的所有部

分都不必執行下去,那么潛在H勺性能提高將是相稱可觀時。

3.1.7按位運算符

按位運完符容許我們操作一種整數主數據類型中口勺單個“比特”,即二進制位。按位運算符會

對兩個自變量中對應的位執行布爾代數,并最終身成一種成果。

按位運算來源于C語言的低級操作。我們常常都要直接操縱硬件,需要頻繁設置硬件寄存器

內的二進制位。JavaIJ勺設計初衷是嵌入電視頂置盒內,因此這種低級操作仍被保留下來了。

然而,由于操作系統的進步,目前也許不必過于頻繁地進行按位運算。

若兩個輸入位都是1,則按位AND運算符(&)在輸出位里生成一種1;否則生成0。若兩個

輸入位里至少有一種是1,則按位OR運算符(I)在輸出位里生成一種1;只有在兩個輸入位

都是0日勺狀況下,它才會生成一種0。若兩個輸入位的某一種是1,但不全都是1,那么按位

XOR(\異或)在輸M位里生成一種1。按位NOT(?,乜叫作“非”運算符)屬于一元運算

符;它只對?種自變量進行操作(其他所有運算符都是二元運算符)。按位NOT生成與輸入位

的相反的值一一若輸入0,則輸出1;輸入1,則輸出0。

按位運算符和邏輯運算符都使用了同樣的字符,只是數量不一樣。因此,我們能以便地記憶

各自的含義:由于“位”是非常“小”的,因此按位運算符僅使用了一種字符。

按位運算符可與等號(:)聯合使用,以便合并運算及賦值:&二,I=和三都是合法的(由于~

是一元運算符,因此不可與二聯合使用)。

我們將boolean(布爾)類型當作一種“單位”或“單比特”值看待,因此它多少有些獨特

的地方。我們可執行按位AND,OR和XOR,但不能執行按位NOT(大概是為了防止與邏輯NOT

混淆)。對于布爾值,按位運算符具有與邏輯運算符相似的效果,只是它們不會中途“短路”。

此外,針對布爾值進行的按位運算為我們新增了一種XOR邏輯運算符,它并未包括在“邏輯”

運算符的列表中。在移位體現式中,我們被嚴禁使用布公運算,原因將在下面解釋。

3.1.8移位運算符

移位運笄符面向的運算對象也是一進制於廣位工可單獨用它們處理整數類型(主類型的一種)。

左移位運算符(?)能將運算符左邊的運算對象向左移動運算符右側指定的I位數(在低位補

0)。“有符號”右移位運算符(?)則將運算符左邊日勺運算對象向右移動運算符右側指定H勺位

數。“有符號”右移位運算符使用了“符號擴展”:若值為正,則在高位插入0;若值為負,

則在高位插入1。Java也添加了一種“無符號”右移位運算符(?>),它使用了“零擴展”:

無論正負,都在高位插入0。這i運算符是C或C++沒有的。

若對char,byte或者short進行移位處理,那么在移位進行之前,它們會自動轉換成?種

into只有右側的5個低位才會用到。這樣可防止我們在一種int數里移動不切實際的位數。

若對一種long值進行處理,最終得到的成果也是long。此時只會用到右側的6個低位,防

止移動超過long值里現成的位數。但在進行“無符號”右移位時,也也許碰到?種問題。若

對byte或short值進行右移位運算,得到的也許不是對的U勺成果(Java1.0和Java1.1尤

其突出)。它們會自動轉換成int類型,并進行右移位。但“零擴展”不會發生,因此在那些

狀況下會得到T的成果。可用下面這個例子檢測自己的實現方案:

//:CRShift.java

//Testofunsignedrightshift

publicclassURShift{

publicstaticvoidmain(String[]args){

inti=-1;

i?>=10;

System.out.println(i);

long1=-1;

1?>=10;

System.out.println(l);

shorts=-1;

s?>=10;

System.out.printin(s);

byteb=-1;

b?>=10;

System.out.println(b);

)

}〃/廣

移位可與等號(<<=或>=或>>>=)組合使用。此時,運算符左邊的值會移動由右邊的值指定

的位數,再將得到的成果賦回左邊日勺值。

下面這個例子向大家闡示了怎樣應用波及“按位”操作時所有運算符,以及它們的效果:

//:BitManipulation.java

//Usingthebitwiseoperators

importjava.util.*;

publicclassBitManipulation{

publicstaticvoidmain(String[]args){

Randomrand=newRandom();

inti=rand,nextlr.t();

intj=rand,nextIr.t();

pBinlnt("T",-1);

pBinlnt('+1”,+1);

intmaxpos=;

pBinlnt("maxpos”,maxpos);

intmaxneg=一;

pBinlnt("maxneg”,maxneg);

pBinlnt("i",i);

pBinlnt~i);

pBinlnt("-i”,-i);

pBinlnt(^j^,j);

pBinlnt("i&j",i&j);

pBinlnt("i|j",i|j);

pBinlnt("i'j",i"j);

pBinlntCi?5〃,i?5);

pBinlnt(〃i?5”,i?5);

pBinlnt(*Ci)?5",Ci)?5);

pBinlnt(〃i?>5”,i?>5);

pBinlntCCi)?>5",Ci)?>5);

long1=rand.nextLongO;

longm=rand.nextLongO;

pBinLong("TL",-IL);

pBinLong("+lL",+1L);

long11=4775807L;

pBinLong(^maxpos^,11);

longlln=-4775808L;

pBinLong("maxneg”,lln);

pBinLong("l",1);

pBinLong'D;

pBinLong(*-K,-1);

pBinLong("m",m);

pBinLong(“1&m〃,1&m);

pBinLong(*lm",1m);

pBinLong(“1m",1m);

pBinLong(“1?5”,1?5);

pBinLong(“1?5”,1?5);

pBinLongC*Cl)?5".(~1)?5);

pBinLong^l?>5〃,1?>5);

pBinLong("(~l)?>5",(~1)>?5);

)

staticvoidpBinlnt(Strings,inti){

System,out.printin(

s+,int:+”,binary:〃);

System.out.print("");

for(intj=31;j>=0;j—)

if(((l?j)&i)!=0)

System,out.print(T);

else

System.out.print("0");

System.out.println();

)

staticvoidpBinLong(Strings,long1){

System,out.println(

s+”,long:binary:");

System,out.print("");

for(inti=63;i>=0;i—)

if(((lL?i)&1)!=0)

System.out.print(T):

else

System,out.prirt(〃0");

System,out.println();

)

}〃/廣

程序末尾調用了兩個措施:pBinlntO和pBinLongO。它們分別操作一種int和long值,并

用一種二進制格式輸出,同步附有簡要的闡明文字。目前,可臨時忽視它們詳細日勺實現方案。

大家要注意口勺是System.out.print。的使用,而不是System.out.printlnO。print。措施

不會產生?種新行,以便在同?行里羅列多種信息。

除展示所有按位運算符針對int和longH勺效果之外,本例也展示了int和long的最小值、

最大值、+1和T值,使大家能體會它們的狀況。注意高位代表正負號:0為正,1為負。下

面列出int部分的輸出:

-1,int:-1,binary:

11111111

+1,int:1,binary:

00000001

maxpos,int:,binary:

11111111

maxneg,int:binary:

00000000

i,int:59081716,binary:

11110100

~i,int:-59081717,binary:

00001011

-i,int:-59081716,binary:

00001100

j,int:,binary:

10001100

i&j,int:58720644,binary:

10000100

iIj,int:,binary:

11111100

i八j,int:,binary:

01111000

i<<5,int:,binary:

10000000

i?5,int:1846303,binary:

00011111

Ci)?5,int:-1846304,binary:

11100000

i?>5,int:1846303,binary:

00011111

Ci)?>5,int:,binary:

11100000

數字的二進制形式體現為“有符號2的補值”。

3.1.9三元if-else運算符

這種運算符比較罕見,由于它有三個運算對象。但它確實屬于運算符FI勺一種,由于它最終也

會生成一種值。這與本章后一節要講述的一般if-else語句是不一樣H勺。體現式采用下述形

式:

布爾體現式?值0:值1

若“布爾體現式”的成果為true,就計算“值()”,并且它的成果成為最終由運算符產生的值。

但若“布爾體現式”的成果為false,計算的J就是“值1”,并且它的成果成為最終由運算符

產生的值。

當然,也可以換用一般的「『else語句(在背面簡介),但三元運算符愈加簡潔。盡管C引認

為傲的就是它是一種簡潔內語言,并且三元運算符的引入多半就是為了體現這種高效率日勺編

程,但假若您打算頻繁用它,還是要先多作某些思量一一它很輕易就會產生可讀性極差啊代

碼。

可將條件運算符用于自己向“副作用”,或用于它生成的值。但一般都應將其用于值,由于那

樣做可將運算符與if-clse明確區別開。下面便是一種例子:

staticintternary(inti){

returni<10?i*100:i*10;

)

可以看出,假設用一般的if-else構造寫上述代碼,代碼量會比上面多出許多。如下所示:

staticintalternative(inti){

if(i<10)

returni*100;

returni*10;

}

但第二種形式更易理解,并且不規定更多的錄入。因此在挑選三元運算符時,請務必權衡?

F利弊。

3.1.10逗號運算符

在C和C++里,逗號不僅作為函數自變量列表的分隔符使用,也作為進行后續計算的一種運

算符使用。在Java里需要用到逗號的唯一場所就是for循環,本章稍后會對此詳加解釋。

3.1.11字串運算符+

這個運算符在Java里有一項特殊用途:連接不一樣的字串。這一點已在前面的例子中展示過

了。盡管與十的老式息義不符,但用+來做這件事情仍然是非常自然的。在C++里,這一功能

看起來非常不錯,因此引入了一項“運算符過載”機制,以便C++程序員為幾乎所有運算符

增長特殊的含義。但非常不幸,與C++的此外某些限制結合,運算符過載成為一種非常復雜

的特性,程序員在設計自己的類時必須對此有周到的考慮。與C++相比,盡管運算符過載在

Java里更易實現,但迄今為止仍然認為這一特性過于復雜。因此Java程序員不能象C++程序

員那樣設計自己的過載運算符。

我們注意到運用“Siring”時某些有趣的現象。若體現式以一種Siring起頭,那么后續所

有運算對象都必須是字串。如下所示:

intx=0,y=1,z=2;

StringsString="x,y,z

System.out.printin(sString+x+y+z);

在這里,Java編譯程序會將x,y和z轉換成它們口勺字串形式,而不是先把它們加到一起。

然而,假如使用下述語句:

System.out.println(x+sString);

那么初期版本"勺Java就會提醒出錯(后來U勺版本能將x轉換成一種字串)。因此,假如想通

過“加號”連接字串(使用Java的初期版本),請務必保證第一種元素是字用(或加上引號

的一系列字符,編譯能將其識別成一種字串)。

3.1.12運算符常規操作規則

使用運算符口勺一種缺陷是括號口勺運用常常輕易搞錯。雖然對一種體現式怎樣計算有絲亳不確

定的原因,都輕易混淆括號H勺使用方法。這個問題在Java里仍然存在。

在C和C++中,一種尤其常見的錯誤如下:

while(x=y){

//...

程序的意圖是測試與否“相等"(==),而不是進行賦值操作。在C和C++中,若y是-一種非

零值,那么這種賦值的成果肯定是true。這樣使也許得到一種無限循環。在Java里,這個

體現式口勺成果并不是布爾值,而編譯器期望的是一種布爾值,并且不會從一種int數值中轉

換得來。因此在編譯時,系統就會提醒出現錯誤,有效地制止我們深入運行程序。因此這個

缺陷在Java里永遠不會導致更嚴重B勺后果。唯?不會得到編譯錯誤H勺時候是x和y都為布爾

值。在這種狀況下,x=y屬于合法體現式。而在上述狀況下,則也許是一種錯誤。

在C和C++里,類似的一種問題是使用按位AND和OR,而不是邏輯AND和OR。按位AND和OR

使用兩個字符之一(&或I〕,而邏輯AND和OR使用兩個相似的字符(&&或||)。就象“二”和

“==”同樣,鍵入一種字符當然要比鍵入兩個簡樸。在Java里,編譯器同樣可■防止這一點,

由于它不容許我們強行使用一種并不屬于的類型。

3.1.13造型運算符

“造型"(Cast)H勺作用是“與一種模型匹配二在合適的時候,Java會將一種數據類型自動

轉換成另一種。例如,假沒我們為浮點變量分派一種整數值,計算機會將int自動轉換成

floato通過造型,我們可明確設置這種類型的轉換,或者在一般沒有也許進行的時候強迫它

進行。

為進行一次造型,要將括號中但愿的數據類型(包括所有修改符)置于其他任何值的左側。

下面是一種例子:

voidcasts(){

inti=200;

long1=(long)i;

long12=(long)200;

)

正如您看到日勺那樣,既可對一種數值進行造型處理,亦可對一種變量進行造型處理。但在這

兒展示日勺兩種狀況卜,造駕均是多出口勺,由于編譯器在必要口勺時候會自動進行int值到long

值的轉換。當然,仍然可以設置一種造型,提醒自己留心,也使程序更清晰。在其他狀況下,

造型只有在代碼編譯時才顯出重要性。

在C和C++中,造型有時會讓人頭痛。在Java里,造型則是一種比較安全的J操作。不過,若

進行?種名為“縮小轉換"(NarrowingConversion)日勺操作(也就是說,腳本是能容納更多

信息的數據類型,將其轉換成容量較小的類型),此時就也許面臨信息丟失的危險。此時,編

譯器會強迫我們進行造型,就好象說:“這也許是一件危險的事情一一假如您想讓我不顧一切

地做,那么對不起,請明確造型。”而對于“放大轉換”(Wideningconversion),則不必進

行明確造型,由于新類型肯定能容納本來類型日勺信息,不會導致任何信息的J丟失。

Java容許我們將任何主類型“造型”為其他任何一種主類型,但布爾值(bollean)要除外,

后者主線不容許進行任何造型處理。“類”不容許進行造型。為了將一種類轉換成另一種,必

須采用特殊的措施(字串是一種特殊的狀況,本書背面會講到將對象造型到一種類型“家族”

里;例如,“橡樹”可造型為“樹”;反之亦然。但對于具他外來類型,如,'巖石",則不能造

型為“樹”)。

1.字面值

最開始的I時候,若在一種程序里插入“字面值"(Literal),編譯器一般能精確懂得要生成什

么樣的類型。但在有些時侯,對于類型卻是曖昧不清日勺。若發生這種狀況,必須對編譯器加

以合適日勺“指導”。措施是用與字面值關聯的字符形式加入某些額外的信息。下面這段代碼向

大家展示了這些字符。

//:Literals,java

classLiterals

charc=Oxffff;//maxcharhexvalue

byteb=0x7f;//maxbytehexvalue

shorts=0x7fff;//maxshorthexvalue

inti1=0x2f;//Hexadecimal(lowercase)

inti2=0X2F;//Hexadecimal(uppercase)

inti3=0177;//Octal(leadingzero)

//HexandOctalsoworkwithlong.

longnl=200L;//longsuffix

longn2=2001;//longsuffix

longn3=200;

//!long16(200);//notallowed

floatf1=1;

floatf2=IF;//floatsuffix

floatf3=If;//floatsuffix

floatf4=le-45f;//10tothepower

floatf5=le+9f;//floatsuffix

doubledl=Id;//doublesuffix

doubled2=ID;//doublesuffix

doubled3=47e47d;//10tothepower

}〃/廣

十六進制(Base16)一一它合用于所有整數數據類型一一用一種前置的Ox或0X指示。并在

背面跟隨采用大寫或小寫形式的0-9以及a-f。若試圖將一種變量初始化成超過自身能力日勺

一種值(無論這個值的數值形式怎樣),編譯器就會向我們匯報一條出錯消息。注意在上述代

碼中,最大日勺十六進制值只會在char,byte以及short身上出現。若超過這,限制,編譯器

會將值自動變成一種int,并告訴我們需要對這一次賦值進行?“縮小造型”。這樣一來,我們

就可清晰獲知自己已超載了邊界。

八進制(Base8)是用數字中的一種前置0以及0-7日勺數位指示的。在C,C++或者Java中,

對二進制數字沒有對應的“字面”表達措施。

字面值后的尾隨字符標志著它的類型。若為大寫或小寫的L,代表long:大寫或小寫的F,

代表float;大寫或小寫的D,則代表double。

指數總是采用一種我們認為很不直觀的記號措施:1.39e-47f。在科學與工程學領域,“e”代

衣自然對數的基數,約等于2.718(Java一種更精確的dwble值采用Math.EH勺形式)。它在

象”1.39XeU勺-47次方”這樣的指數體現式中使用,意味著“1.39X2.718的-47次方”。然

而,自FORTRAN語言發明后,人們自然而然地覺得e代表“10多少次呆”。這種做法顯得頗

為古怪,由于FORTRAN最初面向U勺是科學與工程設計領域。理所當然,它的設計者應對這樣

的混淆概念持謹慎態度(注釋①)。但不管怎樣,這種尤其"勺體現措施在C,C++以及目前"勺

Java中頑固地保留下來了。因此倘若您習慣將e作為自然對數的基數使用,那么在Java中

看到象“1.39e-47r'這樣的體現式時,請轉換您的思維,從程序設計的角度思索它;它真正

的含義是“1.39X10的-47次方二

①:JohnKirkham這樣寫道:“我最早于1962年在一部IBM1620機器上使用FORTRANII。

那時一一包括60年代以及70年代的初期,FORTRAN一直都是使用大寫字母。之因此會出現

這一狀況,也許是由于初期口勺輸入設備大多是老式電傳打字機,使用5位Baudot碼,那種碼

并不具有小寫能力。乘幕體現式中的'E,也肯定是大寫的,因此不會與自然對數日勺基數‘。’

發生沖突,后者必然是小寫的。‘E'這個字母的含義其實很簡樸,就是'Exponential'的)意

思,即'指數'或‘第數',代表計算系統日勺基數-----般都是10。當時,八進制也在程序

員中廣泛使用。盡管我自己未看到它H勺使用,但假若我在乘鞋體現式中看到一種八進制數字,

就會把它認作Base8。我記得第一次看到用小寫'e'表達指數是在70年代末期。我當時也

覺得它極易產生混淆。因比說,這個問題完全是自己‘潛入'FORTRAN里去時,并非一開始

就有。假如你真的想使用自然對數的基數,實際有現成日勺函數可供運用,但它們都是大寫日勺。”

注意假如編譯器可以對的地識別類型,就不必使用尾隨字符。對于下述語句:

longn3=200;

它并不存在含混不清的地方,因此200背面的一種L大可省去。然而,對于下述語句:

floatf4=le-47f;〃1。即J哥數

編譯器一般會將指數作為雙精度數(double)處理,因此假如沒有這個尾隨『、Jf,就會收到

一條出錯提醒,告訴我們須用一種“造型”將double轉換成float。

2.轉型

大家會發現假若對主數據類型執行任何算術或按位運算,只要它們“比int小”(即char,

byle或者shorl),那么在正式執行運算之前,那些值會自動轉換成ini。這樣一來,最終身

成的值就是ini類型。因此只要把一種值賦回較小的類型,就必須使用“造型工此外,由于

是將值賦回給較小的類型,因此也許出現信息丟失口勺狀況)。一般,體現式中最大的數據類型

是決定了體現式最終止果大小口勺那個類型。若將一種float值與一種double值相乘,成果就

是double;如將一種int和一種long值相加,則成果為long。

3.1.14Java沒有“sizeof”

在C和C++中,sizeofO運算符能滿足我們的一項特殊需要:獲知為數據項目分派的字符數

量。在C和C++中,sizeC最常見R勺一種應用就是“移植”。不一

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論