版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
Java程序員面試分類模擬10論述題1.
break、continue以及return有什么區(qū)別正確答案:break、continue以及return的區(qū)別如下:
1)break用于直接強(qiáng)行(江南博哥)跳出當(dāng)前循環(huán),不再執(zhí)行剩余代碼。當(dāng)循環(huán)中遇到break語句時(shí),忽略循環(huán)體中任何其他語句和循環(huán)條件測(cè)試,程序控制在循環(huán)體后面的語句重新開始。所以,當(dāng)多層循環(huán)嵌套,并且break語句出現(xiàn)在嵌套循環(huán)中的內(nèi)層循環(huán)時(shí),它將僅僅只是終止了內(nèi)層循環(huán)的執(zhí)行,而不影響外層循環(huán)的執(zhí)行。
2)continue用于停止當(dāng)次循環(huán),回到循環(huán)起始處,進(jìn)入下一次循環(huán)操作。continue語句之后的語句將不再執(zhí)行,用于跳過循環(huán)體中的一部分語句,也就是不執(zhí)行這部分語句,而不是跳出整個(gè)循環(huán)執(zhí)行下一條語句,這就是continue與break的主要區(qū)別。簡單來說,continue只是中斷一次循環(huán)的執(zhí)行而已。
3)return語句是一個(gè)跳轉(zhuǎn)語句,用來表示從一個(gè)方法返回(返回一個(gè)值或其他復(fù)雜類型),可以使程序控制返回到調(diào)用該方法的地方。當(dāng)執(zhí)行main方法時(shí),return語句可以使程序執(zhí)行返回到Java運(yùn)行系統(tǒng)。
break只能跳出當(dāng)前的循環(huán),那么如何才能跳出多重循環(huán)呢?可以在多重循環(huán)的外面定義一個(gè)標(biāo)識(shí),然后在循環(huán)體里使用帶有標(biāo)識(shí)的break語句,這樣即可跳出多重循環(huán),示例如下:
publicclassBreak{
publicstaticvoidmain(String[]args){
out:
for(inti=0;i<5;i++){
for(intj=0;j<5;j++){
if(j>=2)
breakout:
System.out.println(j);
}
}
System.out.println("break");
}
程序運(yùn)行結(jié)果為:
0
1
break
上例中,當(dāng)內(nèi)部循環(huán)執(zhí)行到j(luò)等于2時(shí),程序跳出雙重循環(huán),執(zhí)行System.out.println("break")語句。
引申:Java語言中是否存在goto關(guān)鍵字?
雖然關(guān)鍵字goto作為Java的保留字,但目前并沒有在Java中使用。在C/C++中,goto常被用于跳出多重循環(huán),而在。Java語言中,可以使用break和continue來達(dá)到同樣的效果。那么,既然goto沒有在Java語言中使用,為什么還要把它作為保留字呢?其中一個(gè)原因就是這個(gè)關(guān)鍵字有可能會(huì)在將來被使用。如果現(xiàn)在不把goto作為保留字,開發(fā)人員就有可能用goto作為變量名來使用。一旦有一天Java支持goto關(guān)鍵字了,這會(huì)導(dǎo)致以前的程序無法正常運(yùn)行,因此把goto作為保留字是非常有必要的。
這里需要注意的是,在Java語言中,雖然沒有g(shù)oto語句,但是卻能使用標(biāo)識(shí)符加冒號(hào)(:)的形式定義標(biāo)簽,如“mylabel:”,這主要是為了在多重循環(huán)中方便使用break和coutinue而設(shè)計(jì)的。
2.
final、finally和finalize有什么區(qū)別正確答案:final、finally和finalize的區(qū)別如下:
1)final用于聲明屬性、方法和類,分別表示屬性不可變、方法不可覆蓋和類不可被繼承(不能再派生出新的子類)。
final屬性:被final修飾的變量不可變。由于不可變有兩重含義:一是引用不可變;二是對(duì)象不可變。那么,final到底指的是哪種含義呢?下面通過一個(gè)例子來進(jìn)行說明。publicclassTest{publicstaticvoidmain(String[]arg){finalStringBuffers=newStringBuffer("Hello"。s.append("word");System.out.println(s);}}publicclassTest{publicstaticvoidmain(String[]arg){finalStringBuffers=newStringBuffer("Hello");s=newStringBuffer("Helloworld");}}運(yùn)行結(jié)果為:Helloworld運(yùn)行結(jié)果為:編譯期間錯(cuò)誤
從以上的例子中可以看出,final指的是引用的不可變性,即它只能指向初始時(shí)指向的那個(gè)對(duì)象,而不關(guān)心指向?qū)ο髢?nèi)容的變化。所以,被final修飾的變量必須被初始化。一般可以通過以下幾種方式對(duì)其進(jìn)行初始化:①在定義的時(shí)候初始化。②final成員變量可以在初始化塊中初始化,但不可在靜態(tài)初始化塊中初始化。③靜態(tài)final成員變量可以在靜態(tài)初始化塊中初始化,但不可在初始化塊中初始化。④在類的構(gòu)造器中初始化,但靜態(tài)final成員變量不可以在構(gòu)造函數(shù)中初始化。
final方法:當(dāng)一個(gè)方法聲明為final時(shí),該方法不允許任何子類重寫這個(gè)方法,但子類仍然可以使用這個(gè)方法。另外,還有一種被稱為inline(內(nèi)聯(lián))的機(jī)制,當(dāng)調(diào)用一個(gè)被聲明為final的方法時(shí),直接將方法主體插入到調(diào)用處,而不是進(jìn)行方法調(diào)用(類似于C++中的inline),這樣做能提高程序的效率。
final參數(shù):用來表示這個(gè)參數(shù)在這個(gè)函數(shù)內(nèi)部不允許被修改。
final類:當(dāng)一個(gè)類被聲明為final時(shí),此類不能被繼承,所有方法都不能被重寫。但這并不表示final類的成員變量也是不可改變的,要想做到final類的成員變量不可改變,必須給成員變量增加final修飾。值得注意的是,一個(gè)類不能既被聲明為abstract,又被聲明為final。
2)finally作為異常處理的一部分,它只能用在try/catch語句中,并且附帶一個(gè)語句塊,表示這段語句最終一定被執(zhí)行,經(jīng)常被用在需要釋放資源的情況下。
示例1:不使用finally的代碼如下所示:
Connectionconn;
Statementstmt;
try{
conn=DriverManager.getConnection(url1,userName,password);
stmt=conn.createStatement();
stmt.executeUpdate(update);//執(zhí)行一條update語句,此時(shí)出現(xiàn)異常
stmt.close();
conn.close();
}catch(Exceptione){
}
在上面的程序片段中,如果程序在運(yùn)行過程中沒有發(fā)生異常,那么數(shù)據(jù)庫的連接能夠得到釋放,程序運(yùn)行沒有問題。如果在執(zhí)行update語句時(shí)出現(xiàn)異常,后面的close()方法將不會(huì)被調(diào)用,數(shù)據(jù)庫的連接將得不到釋放。如果這樣的程序長期運(yùn)行,將會(huì)耗光數(shù)據(jù)庫的連接資源。通過使用finally可以保證任何情況下數(shù)據(jù)庫的連接資源都能夠被釋放。
示例2:使用finally的代碼如下所示。
Connectionconn=null;
Statementstmt=null;
try{
conn=DriverManager.getConnection(url1,userName,password);
stmt=conn.createStatement();
stmt.executeUpdate(update);//執(zhí)行一條update語句,此時(shí)出現(xiàn)異常
stmt.close();
conn.close();
}catch(Exceptione)finally{
if(stmt!=NULL)
stmt.close();
if(conn!=NULL)
conn.close();
}
在示例2中,不管程序運(yùn)行是否會(huì)出現(xiàn)異常,finally中的代碼一定會(huì)執(zhí)行,這樣能夠保證在任何情況下數(shù)據(jù)庫的連接資源都能被釋放。
3)finalize是Object類的一個(gè)方法,在垃圾回收器執(zhí)行時(shí)會(huì)調(diào)用被回收對(duì)象的finalize()方法,可以覆蓋此方法來實(shí)現(xiàn)對(duì)其他資源的回收,例如關(guān)閉文件等。需要注意的是,一旦垃圾回收器準(zhǔn)備好釋放對(duì)象占用的空間,將首先調(diào)用其finalize()方法,并且在下一次垃圾回收動(dòng)作發(fā)生時(shí),才會(huì)真正回收對(duì)象占用的內(nèi)存。
常見筆試題:
JDK中哪些類是不能繼承的?
答案:從上面的介紹可以知道,不能繼承的類是那些用final關(guān)鍵字修飾的類。一般比較基本的類型為防止擴(kuò)展類無意間破壞原來方法的實(shí)現(xiàn)的類型都應(yīng)該是final的,在JDK中,String、StringBuffer等都是基本類型,所以,String、StringBuffer等類是不能繼承的。
3.
assert有什么作用正確答案:斷言(assert)作為一種軟件調(diào)試的方法,提供了一種在代碼中進(jìn)行正確性檢查的機(jī)制,目前很多開發(fā)語言都支持這種機(jī)制。它的主要作用是對(duì)一個(gè)boolean表達(dá)式進(jìn)行檢查,一個(gè)正確運(yùn)行的程序必須保證這個(gè)boolean表達(dá)式的值為true,若boolean表達(dá)式的值為false,則說明程序已經(jīng)處于一種不正確的狀態(tài)下,系統(tǒng)需要提供告警信息并且退出程序。在實(shí)際的開發(fā)中,assert主要用來保證程序的正確性,通常在程序開發(fā)和測(cè)試時(shí)使用。為了提高程序運(yùn)行的效率,在軟件發(fā)布后,assert檢查默認(rèn)是被關(guān)閉的。
assert包括兩種表達(dá)式,分別為assertexpression1與assertexpression1:expression2,其中,expression1表示一個(gè)boolean表達(dá)式,expression2表示一個(gè)基本類型或者是一個(gè)對(duì)象,基本類型包括boolean、char、double、float、int和long。以下是對(duì)這兩個(gè)表達(dá)式的應(yīng)用。
publicclassTest{
publicstaticvoidmain(String[]args){
assert1+1==2;
System.out.println("assert1ok");
assert1+1==3:"assertfaild,exit";
System.out.println("assert2ok");
}
}
對(duì)于上述代碼,當(dāng)執(zhí)行指令javacTest.Java與javaTest時(shí),程序的輸出結(jié)果為:
assert1ok
assert2ok
對(duì)于上述代碼,當(dāng)執(zhí)行指令javacTest.Java和java-eaTest時(shí)(注意:Java-eaTest的意思是打開-ea開關(guān)),程序的輸出結(jié)果為:
assert1ok
Exceptioninthread"main"Java.lang.AssertionError:assertfaild,exit
atTest.main(Test.Java:5)
assert的應(yīng)用范圍很多,主要包括①檢查控制流;②檢查輸入?yún)?shù)是否有效;③檢查函數(shù)結(jié)果是否有效;④檢查程序不變量。雖然assert的功能與if判斷類似,但二者存在著本質(zhì)的區(qū)別:assert一般在調(diào)試程序時(shí)使用,但如果不小心用assert來控制了程序的業(yè)務(wù)流程,那在調(diào)試結(jié)束后去掉assert就意味著修改了程序的正常邏輯,這樣的做法是非常危險(xiǎn)的;而if判斷是邏輯判斷,本身就是用以控制程序流程的。
需要注意的是,在Java語言中,assert與C語言中的assert盡管功能類似,但也不完全一樣,具體表現(xiàn)為兩個(gè)方面的不同:①Java語言中是使用assert關(guān)鍵字去實(shí)現(xiàn)其功能,而C語言中使用的是庫函數(shù);②C語言中的assert是在編譯時(shí)開啟,而Java語言中則是在運(yùn)行時(shí)開啟。
4.
static關(guān)鍵字有哪作用正確答案:static關(guān)鍵字主要有兩種作用:第一,為某特定數(shù)據(jù)類型或?qū)ο蠓峙鋯我坏拇鎯?chǔ)空間,而與創(chuàng)建對(duì)象的個(gè)數(shù)無關(guān)。第二,實(shí)現(xiàn)某個(gè)方法或?qū)傩耘c類而不是對(duì)象關(guān)聯(lián)在一起,也就是說,在不創(chuàng)建對(duì)象的情況下就可以通過類來直接調(diào)用方法或使用類的屬性。具體而言,在Java語言中,static主要有4種使用情況:成員變量、成員方法、代碼塊和內(nèi)部類。
(1)static成員變量
雖然Java語言中沒有全局的概念,但可以通過static關(guān)鍵字來達(dá)到全局的效果。Java類提供了兩種類型的變量:用static關(guān)鍵字修飾的靜態(tài)變量和不用static關(guān)鍵字修飾的實(shí)例變量。靜態(tài)變量屬于類,在內(nèi)存中只有一個(gè)復(fù)制(所有實(shí)例都指向同一個(gè)內(nèi)存地址),只要靜態(tài)變量所在的類被加載,這個(gè)靜態(tài)變量就會(huì)被分配空間,因此就可以被使用了。對(duì)靜態(tài)變量的引用有兩種方式,分別為“類.靜態(tài)變量”和“對(duì)象.靜態(tài)變量”。
實(shí)例變量屬于對(duì)象,只有對(duì)象被創(chuàng)建后,實(shí)例變量才會(huì)被分配空間,才能被使用,它在內(nèi)存中存在多個(gè)復(fù)制。只能用“對(duì)象.實(shí)例變量”的方式來引用。以下是靜態(tài)變量與實(shí)例變量的使用示例。
publicclassTestAttribute{
publicstaticintstaticInt=0;
publicintnonStaticInt=0;
publicstaticvoidmain(String[]args){
TestAttributet=newTestAttribute();
system.out.println("t.staticInt="+t.staticInt);
system.out.println("TestAttribute.staticInt="+TestAttribute.staticInt);
system.out.println("t.nonStaticIn!="+t.nonStaticInt);
System.out.println("對(duì)靜態(tài)變量和實(shí)例變量分別+1");
t.staticInt++;
t.nonStaticInt++;
TestAttributet1=newTestAttribute();
System.out.println("t1.staticInt="+t1.staticInt);
System.out.println("TestAttribute.staticInt="+TestAttribute.staticInt);
System.out.println("t1.nonStaticInt="+t1.nonStaticInt);
}
}
程序運(yùn)行結(jié)果為:
t.staticInt=0
TestAttribute.staticInt=0
t.nonStaticInt=0
對(duì)靜態(tài)變量和實(shí)例變量分別+1
t1.staticInt=1
TestAttribute.staticInt=1
t1.nonStaticInt=0
從上例可以看出,靜態(tài)變量只有一個(gè),被類擁有,所有對(duì)象都共享這個(gè)靜態(tài)變量,而實(shí)例對(duì)象是與具體對(duì)象相關(guān)的。需要注意的是,與C++語言不同的是,在Java語言中,不能在方法體中定義static變量。
(2)static成員方法
與變量類似,Java類同時(shí)也提供了static方法與非static方法。static方法是類的方法,不需要?jiǎng)?chuàng)建對(duì)象就可以被調(diào)用,而非static方法是對(duì)象的方法,只有對(duì)象被創(chuàng)建出來后才可以被使用。
static方法中不能使用this和super關(guān)鍵字,不能調(diào)用非static方法,只能訪問所屬類的靜態(tài)成員變量和成員方法,因?yàn)楫?dāng)static方法被調(diào)用時(shí),這個(gè)類的對(duì)象可能還沒被創(chuàng)建,即使已經(jīng)被創(chuàng)建了,也無法確定調(diào)用哪個(gè)對(duì)象的方法。同理,static方法也不能訪問非static類型的變量。
static一個(gè)很重要的用途是實(shí)現(xiàn)單例模式。單例模式的特點(diǎn)是該類只能有一個(gè)實(shí)例,為了實(shí)現(xiàn)這一功能,必須隱藏類的構(gòu)造函數(shù),即把構(gòu)造函數(shù)聲明為private,并提供一個(gè)創(chuàng)建對(duì)象的方法,由于構(gòu)造對(duì)象被聲明為private,外界無法直接創(chuàng)建這個(gè)類型的對(duì)象,只能通過該類提供的方法來獲取類的對(duì)象,要達(dá)到這樣的目的只能把創(chuàng)建對(duì)象的方法聲明為static,程序示例如下:
classSingleton{
privatestaticSingletoninstance=null;
privateSingleton(){}
publicstaticSingletongetInstance(){
if(instance==null){
instance=newSingleton();
}
returninstance;
}
}
用public修飾的static變量和方法本質(zhì)上都是全局的,若在static變量前用private修飾,則表示這個(gè)變量可以在類的靜態(tài)代碼塊或者類的其他靜態(tài)成員方法中使用,但是不能在其他類中通過類名來直接引用。
(3)static代碼塊
static代碼塊(靜態(tài)代碼塊)在類中是獨(dú)立于成員變量和成員函數(shù)的代碼塊的。它不在任何一個(gè)方法體內(nèi),JVM在加載類時(shí)會(huì)執(zhí)行static代碼塊,如果有多個(gè)static代碼塊,JVM將會(huì)按順序來執(zhí)行。static代碼塊經(jīng)常被用來初始化靜態(tài)變量。需要注意的是,這些static代碼塊只會(huì)被執(zhí)行一次,示例如下:
publicclassTest{
privatestaticinta;
static{
Test.a=4;
System.out.println(a);
System.out.println("staticblockiscalled");
publicstaticvoidmain(String[]args){
}
程序運(yùn)行結(jié)果為:
4
staticblockiscalled
(4)static內(nèi)部類
static內(nèi)部類是指被聲明為static的內(nèi)部類,它可以不依賴于外部類實(shí)例對(duì)象而被實(shí)例化,而通常的內(nèi)部類需要在外部類實(shí)例化后才能實(shí)例化。靜態(tài)內(nèi)部類不能與外部類有相同的名字,不能訪問外部類的普通成員變量,只能訪問外部類中的靜態(tài)成員和靜態(tài)方法(包括私有類型),示例如下:
publicClassOuter{
staticintn=5;
staticClassInner{
voidaccessAttrFromOuter(){
System.out.println("Inner:Outer.n="+n);
}
}
publicstaticvoidmain(String[]args){
Outer.Innernest=newOuter.Inner();
nest.accessAttrFromOuter();
}
}
程序運(yùn)行結(jié)果為:
Inner:Outer.n=5
需要注意的是,只有內(nèi)部類才能被定義為static。
引申:
1.什么是實(shí)例變量?什么是局部變量?什么是類變量?什么是final變量?
實(shí)例變量:變量歸對(duì)象所有(只有在實(shí)例化對(duì)象后才可以)。每當(dāng)實(shí)例化一個(gè)對(duì)象時(shí),會(huì)創(chuàng)建一個(gè)副本并初始化,如果沒有顯示初始化,那么會(huì)初始化一個(gè)默認(rèn)值。各個(gè)對(duì)象中的實(shí)例變量互不影響。
局部變量:在方法中定義的變量,在使用前必須初始化。
類變量:用static可修飾的屬性、變量歸類所有,只要類被加載,這個(gè)變量就可以被使用(類名.變量名)。所有實(shí)例化的對(duì)象共享類變量。
final變量:表示這個(gè)變量為常量,不能被修改。
2.static與final結(jié)合使用表示什么意思?
在Java語言中,static關(guān)鍵字常與final關(guān)鍵字結(jié)合使用,用來修飾成員變量與成員方法,有點(diǎn)類似于C/C++語言中的“全局常量”。對(duì)于變量,若使用staticfinal修飾,則表示一旦賦值,就不可修改,并且通過類名可以訪問。對(duì)于方法,若使用staticfinal修飾,則表示該方法不可覆蓋,并且可以通過類名直接訪問。
常見筆試題:
publicclassTest{
publicstaticinttestStatic(){
staticfinalinti=0;
system.out.println(i++);
publicstaticvoidmain(Stringargs[]){
Testtest=newTest();
test.testStatic();
}
上述程序的運(yùn)行結(jié)果是什么?______
A.0
B.1
C.2
D.編譯失敗
答案:D。在Java語言中,不能在成員函數(shù)內(nèi)部定義static變量。
5.
使用switch時(shí)有哪注意事項(xiàng)正確答案:switch語句用于多分支選擇,在使用switch(expr)時(shí),expr只能是一個(gè)枚舉常量(內(nèi)部也是由整型或字符類型實(shí)現(xiàn))或一個(gè)整數(shù)表達(dá)式,其中整數(shù)表達(dá)式可以是基本類型int或其對(duì)應(yīng)的包裝類Integer,當(dāng)然也包括不同的長度整型,例如short。由于byte、short和char類型的值都能夠被隱式地轉(zhuǎn)換為int類型,因此這些類型以及它們對(duì)應(yīng)的包裝類型都可以作為switch的表達(dá)式。但是,long、float、double、String類型不能夠隱式地轉(zhuǎn)換為int類型,因此它們不能被用作switch的表達(dá)式。如果一定要使用long、float,或double作為switch的參數(shù),必須將其強(qiáng)制轉(zhuǎn)換為int型才可以,例如,以下對(duì)switch中參數(shù)的使用就是非法的。
floata=0.123;
switch(a)//錯(cuò)誤!a不是整型或字符類型變量。
{
...
}
另外,與switch對(duì)應(yīng)的是case語句,case語句之后可以是直接的常量數(shù)值,例如1、2,也可以是一個(gè)常量計(jì)算式,例如1+2等,還可以是final型的變量(final變量必須是編譯時(shí)的常量),例如finalinta=0,但不能是變量或帶有變量的表達(dá)式,例如i*2等。當(dāng)然更不能是浮點(diǎn)型數(shù),例如1.1或者1.2/2等。
switch(formWay)
{
case2-1://正確
...
casea-2://錯(cuò)誤
...
case2.0://錯(cuò)誤
...
}
隨著Java語言的發(fā)展,在Java7中,switch開始支持String類型了。以下是一段支持String類型的示例代碼:
publicclassTest{
publicvoidtest(Stringstr){
switch(str){
case"hehao":
System.out.println("hehao");
break;
case"xuepeng";
System.out.println("xuepeng");
break;
case"yexiangyang":
System.out.println("yexiangyang");
break;
default:
System.out.println("default");
}
}
}
從本質(zhì)上來講,switch對(duì)字符串的支持,其實(shí)是int類型值的匹配。它的實(shí)現(xiàn)原理如下:通過對(duì)case后面的String對(duì)象調(diào)用hashCode()方法,得到一個(gè)int類型的hash值,然后用這個(gè)hash值來唯一標(biāo)識(shí)這個(gè)case。那么當(dāng)匹配時(shí),首先調(diào)用這個(gè)字符串hashCode()函數(shù),獲取一個(gè)hash值(int類型),用這個(gè)hash值來匹配所有case,如果沒有匹配成功,說明不存在;如果匹配成功了,接著會(huì)調(diào)用字符串的String.equals()方法進(jìn)行匹配(至于為什么需要調(diào)用equals()方法)。由此可以看出,String變量不能為null,同時(shí),switch的case子句中使用的字符串也不能為null。
在使用switch時(shí),需要注意另外一個(gè)問題:一般必須在case語句結(jié)尾添加break語句。因?yàn)橐坏┩ㄟ^switch語句確定了入口點(diǎn),就會(huì)順序執(zhí)行后面的代碼,直到遇到關(guān)鍵字break。否則,會(huì)執(zhí)行滿足這個(gè)case之后的其他case的語句而不管case是否匹配,直到switch結(jié)束或者遇到break為止。如果在switch中省略了break語句,那么匹配的case值后的所有情況(包括default情況)都會(huì)被執(zhí)行,示例如下:
publicclassTest{
publicstaticvoidmain(String[]args){
intx=4;
switch(x)
case1:System.out.println(x);
case2:System.out.println(x);
case3:System.out.println(x);
case4:System.out.println(x);
case5:System.out.println(x);
(default:System.out.println(x);
}
}
}
程序運(yùn)行結(jié)果為:
4
4
4
6.
volatile有什么作用正確答案:在用Java語言編寫的程序中,有時(shí)為了提高程序的運(yùn)行效率,編譯器會(huì)自動(dòng)對(duì)其進(jìn)行優(yōu)化,把經(jīng)常被訪問的變量緩存起來,程序在讀取這個(gè)變量時(shí)有可能會(huì)直接從緩存(例如寄存器)中來讀取這個(gè)值,而不會(huì)去內(nèi)存中讀取。這樣做的一個(gè)好處是提高了程序的運(yùn)行效率,但當(dāng)遇到多線程編程時(shí),變量的值可能因?yàn)閯e的線程而改變了,而該緩存的值不會(huì)相應(yīng)改變,從而造成應(yīng)用程序讀取的值和實(shí)際的變量值不一致,例如,在本次線程內(nèi),當(dāng)讀取一個(gè)變量時(shí),為提高存取速度,會(huì)先把變量讀取到一個(gè)緩存中,當(dāng)以后再取變量值時(shí),就直接從緩存中取值,當(dāng)變量值在本線程里改變時(shí),會(huì)同時(shí)把變量的新值復(fù)制到該緩存中,以便保持一致。
volatile是一個(gè)類型修飾符(typespecifier),它是被設(shè)計(jì)用來修飾被不同線程訪問和修改的變量。被volatile類型定義的變量,系統(tǒng)每次用到它時(shí)都是直接從對(duì)應(yīng)的內(nèi)存當(dāng)中提取,而不會(huì)利用緩存。在使用了volatile修飾成員變量后,所有線程在任何時(shí)候所看到變量的值都是相同的。下面給出一個(gè)使用volatile的示例。
publicclassMyThreadimplementsRunnable{
privatevolatileBooleanflag;
publicvoidstop(){
flag=false;
}
publicvoidrun(){
while(flag)
;//dosomething
}
}
以上代碼示例是用來停止線程最常用的一種方法,如果boolean類型的變量flag沒有被聲明為volatile,那么,當(dāng)這個(gè)線程的run方法在判斷flag值時(shí),使用的有可能是緩存中的值,此時(shí)就不能及時(shí)地獲取其他線程對(duì)flag所做的操作,因此會(huì)導(dǎo)致線程不能及時(shí)地停止。
需要注意的是,由于volatile不能保證操作的原子性,因此,一般情況下volatile不能代替sychronized。此外,使用volatile會(huì)阻止編譯器對(duì)代碼的優(yōu)化,因此會(huì)降低程序的執(zhí)行效率。所以,除非迫不得已,否則,能不使用volatile就盡量不要使用volatile。
7.
instanceof有什么作用正確答案:instanceof是Java語言中的一個(gè)二元運(yùn)算符,它的作用是判斷一個(gè)引用類型的變量所指向的對(duì)象是否是一個(gè)類(或接口、抽象類、父類)的實(shí)例,即它左邊的對(duì)象是否是它右邊的類的實(shí)例該運(yùn)算符返回boolean類型的數(shù)據(jù)。
常見的用法為:result=objectinstanceofclass。如果object是class的一個(gè)實(shí)例,那么instanceof運(yùn)算符返回true;如果object不是Class的一個(gè)實(shí)例,或者object是null,那么instanceof運(yùn)算符返回false。
以如下程序?yàn)槔?/p>
publicclassTest{
publicstaticvoidmain(Stringargs[]){
StringS="Hello";
int[]a={1,2};
if(sinstanceofString)
System.out.println("true");
if(sinstanceofObject)
System.out.println("true");
if(ainstanceofint[])
System.out.println("true");
}
}
程序運(yùn)行結(jié)果為:
true
true
true
8.
strictfp有什么作用正確答案:關(guān)鍵字strictfp是strictfloatpoint的縮寫,指的是精確浮點(diǎn),它用來確保浮點(diǎn)數(shù)運(yùn)算的準(zhǔn)確性。JVM在執(zhí)行浮點(diǎn)數(shù)運(yùn)算時(shí),如果沒有指定strictfp關(guān)鍵字,此時(shí)計(jì)算結(jié)果可能會(huì)不精確,而且計(jì)算結(jié)果在不同平臺(tái)或廠商的虛擬機(jī)上會(huì)有不同的結(jié)果,導(dǎo)致意想不到的錯(cuò)誤。而一旦使用了strictfp來聲明一個(gè)類、接口或者方法,那么在所聲明的范圍內(nèi),Java編譯器以及運(yùn)行環(huán)境會(huì)完全依照IEEE二進(jìn)制浮點(diǎn)數(shù)算術(shù)標(biāo)準(zhǔn)(IEEE754)來執(zhí)行,在這個(gè)關(guān)鍵字聲明的范圍內(nèi)所有浮點(diǎn)數(shù)的計(jì)算都是精確的。需要注意的是,當(dāng)一個(gè)類被strictfp修飾時(shí),所有方法都會(huì)自動(dòng)被strictfp修飾。因此,strictfp可以保證浮點(diǎn)數(shù)運(yùn)算的精確性,而且在不同的硬件平臺(tái)上會(huì)有一致的運(yùn)行結(jié)果。下例給出了strictfp修飾類的使用方法:
publicstrictfpclassTest{
publicstaticvoidtestStrictfp(){
floatf=0.12365f;
doubled=0.03496421d;
doublesum=f+d;
System.out.println(sum);
}
publicstaticvoidmain(String[]args)}
testStrictfp();
}
}
程序運(yùn)行結(jié)果為:
0.15861420949932098
9.
Java提了哪基本數(shù)據(jù)類型正確答案:Java語言一共提供了8種原始的數(shù)據(jù)類型(byte,short,int,long,float,double,char,boolean),這些數(shù)據(jù)類型不是對(duì)象,而是Java語言中不同于類的特殊類型,這些基本類型的數(shù)據(jù)變量在聲明之后就會(huì)立刻在棧上被分配內(nèi)存空間。除了這8種基本的數(shù)據(jù)類型外,其他類型都是引用類型(例如類、接口、數(shù)組等),引用類型類似于C++中的引用或指針的概念,它以特殊的方式指向?qū)ο髮?shí)體,這類變量在聲明時(shí)不會(huì)被分配內(nèi)存空間,只是存儲(chǔ)了一個(gè)內(nèi)存地址而已。
下表為Java中的基本數(shù)據(jù)類型及其描述。不同數(shù)據(jù)類型對(duì)比數(shù)據(jù)類型字節(jié)長度范圍默認(rèn)值包裝類int4[-2147483648,2147483647](-231~231-1)0Integershort2[-32768,32767]0Shortlong8[-9223372036854775808,9223372036854775807](-263~263-1)0L或0lLongbyte1[-128,127]0Bytefloat432位IEEE754單精度范圍0.0F或0.0fFloatdouble864位IEEE754雙精度范圍0.0Doublechar2Unicode[0,65535]u0000Characterboolean1true和falsefalseBoolean
以上這些基本類型可以分為如下4種類型:
1)int長度數(shù)據(jù)類型:byte(8bit)、short(16bit)、int(32bit)、long(64bit)。
2)float長度數(shù)據(jù)類型:單精度(32bitfloat)、雙精度(64bitdouble)。
3)boolean類型變量的取值:true、false。對(duì)于boolean占用空間的大小,從理論上講,只需要1bit就夠了,但在設(shè)計(jì)的時(shí)候?yàn)榱丝紤]字節(jié)對(duì)齊等因素,一般會(huì)考慮使其占用一個(gè)字節(jié)。由于Java規(guī)范沒有明確的規(guī)定,因此,不同的JVM可能會(huì)有不同的實(shí)現(xiàn)。
4)char數(shù)據(jù)類型:unicode字符(16bit)。
此外,Java語言還提供了對(duì)這些原始數(shù)據(jù)類型的封裝類(字符類型Character,布爾類型Boolean,數(shù)值類型Byte、Short、Integer、Long、Float、Double)。需要注意的是,Java中的數(shù)值類型都是有符號(hào)的,不存在無符號(hào)的數(shù),它們的取值范圍也是固定的,不會(huì)隨著硬件環(huán)境或者操作系統(tǒng)的改變而改變。除了以上提到的8種基本數(shù)據(jù)類型以外,在Java語言中,還存在另外一種基本類型void,它也有對(duì)應(yīng)的封裝類java.lang.void,只是無法直接對(duì)它進(jìn)行操作而已。封裝類型和原始類型有許多不同點(diǎn):首先,原始數(shù)據(jù)類型在傳遞參數(shù)時(shí)都是按值傳遞,而封裝類型是按引用傳遞的。其次,當(dāng)封裝類型和原始類型用作某個(gè)類的實(shí)例數(shù)據(jù)時(shí),它們所指定的默認(rèn)值不同。對(duì)象引用實(shí)例變量的默認(rèn)值為null,而原始類型實(shí)例變量的默認(rèn)值與它們的類型有關(guān)(例如int默認(rèn)初始化為0),示例如下:
publicclassTest{
Strings;
inti;
floatf;
publicstaticvoidmain(Stringargs[]){
Testt=newTest();
System.out.println(t.s==null);
System.out.println(t.i);
System.out.println(t.f);
}
}
程序運(yùn)行結(jié)果為:
true
0
0.0
除了以上需要注意的內(nèi)容外,在Java語言中,默認(rèn)聲明的小數(shù)是double類型的,因此在對(duì)float類型的變量進(jìn)行初始化時(shí)需要進(jìn)行類型轉(zhuǎn)換。float類型的變量有兩種初始化方法:floatf=1.0f或floatf=(float)1.0。與此類似的是,在Java語言中,直接寫的整型數(shù)字是int類型的,如果在給數(shù)據(jù)類型為long的變量直接賦值時(shí),int類型的值無法表示一個(gè)非常大的數(shù)字,因此,在賦值時(shí)可以通過如下的方法來賦值:longl=26012402244L。
引申:
1.在Java語言中null值是什么?在內(nèi)存中null是什么?
null不是一個(gè)合法的Object實(shí)例,所以編譯器并沒有為其分配內(nèi)存,它僅僅用于表明該引用目前沒有指向任何對(duì)象。其實(shí),與C語言類似,null是將引用變量的值全部置0。
2.如何理解賦值語句Stringx=null?
在Java語言中,變量被分為兩大類型:原始值(primitive)與引用值(reference)。聲明為原始類型的變量,其存儲(chǔ)的是實(shí)際的值。聲明為引用類型的變量,存儲(chǔ)的是實(shí)際對(duì)象的地址(指針,引用)。對(duì)于賦值語句Stringx=null,它定義了一個(gè)變量“x”,x中存放的是String引用,此處為null。
常見筆試題:
1.下列表達(dá)式中,正確的是______。
A.byteb=128;
B.booleanflag=null;
C.floatf=0.9239;
D.longa=2147483648L;
答案:D。A中byte能表示的取值范圍為[-128,127],因此不能表示128。B中boolean的取值只能是true或false,不能為null。C中0.9239為double類型,需要進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換。
2.String是最基本的數(shù)據(jù)類型嗎?
答案:不是。基本數(shù)據(jù)類型包括byte、int、char、long、float、double:、boolean和short。
3.int和Integer有什么區(qū)別?
答案:Java語言提供兩種不同的類型,即引用類型和原始類型(或內(nèi)置類型)。int是Java語言的原始數(shù)據(jù)類型,Integer是Java語言為int提供的封裝類。Java為每個(gè)原始類型提供了封裝類。
引用類型與原始類型的行為完全不同,并且它們具有不同的語義。而且,引用類型與原始類型具有不同的特征和用法。
4.賦值語句floatf=3.4是否正確?
答案:不正確。數(shù)據(jù)3.4默認(rèn)情況下是double類型,即雙精度浮點(diǎn)數(shù),將double類型數(shù)值賦值給float類型的變量,會(huì)造成精度損失,因此需要對(duì)其進(jìn)行強(qiáng)制類型轉(zhuǎn)換,即將3.4轉(zhuǎn)換成float類型或者將3.4強(qiáng)制寫成float類型。所以,floatf=(float)3.4或者floatf=3.4F寫法都是可以的。
10.
什么是不可變類正確答案:不可變類(immutableclass)是指當(dāng)創(chuàng)建了這個(gè)類的實(shí)例后,就不允許修改它的值了,也就是說,一個(gè)對(duì)象一旦被創(chuàng)建出來,在其整個(gè)生命周期中,它的成員變量就不能被修改了。它有點(diǎn)類似于常量(const),即只允許別的程序讀,不允許別的程序進(jìn)行修改。
在Java類庫中,所有基本類型的包裝類都是不可變類,例如Integer、Float等。此外,String也是不可變類??赡苡腥藭?huì)有疑問,既然String是不可變類,為什么還可以寫出如下代碼來修改String類型的值呢?
publicclassTest{
publicstaticvoidmain(String[]args){
Strings="Hello";
s+="world";
system.out.println(s);
}
}
程序運(yùn)行結(jié)果為:
Helloworld
表面上看,好像是修改String類型對(duì)象s的值。其實(shí)不是,Strings=“Hello”語句聲明了一個(gè)可以指向String類型對(duì)象的引用,這個(gè)引用的名字為s,它指向了一個(gè)字符串常量“Hello”。s+="world"并沒有改變s所指向的對(duì)象(由于“Hello”是String類型的對(duì)象,而String又是不可變量),這句代碼運(yùn)行后,s指向了另外一個(gè)String類型的對(duì)象,該對(duì)象的內(nèi)容為“Helloworld”。原來的那個(gè)字符串常量“Hello”還存在于內(nèi)存中,并沒有被改變。
在介紹完不可變類的基本概念后,下面主要介紹如何創(chuàng)建一個(gè)不可變類。通常來講,要?jiǎng)?chuàng)建一個(gè)不可變類需要遵循下面4條基本原則:
1)類中所有成員變量被private所修飾。
2)類中沒有寫或者修改成員變量的方法,例如setxxx,只提供構(gòu)造函數(shù),一次生成,永不改變。
3)確保類中所有方法不會(huì)被子類覆蓋,可以通過把類定義為final或者把類中的方法定義為final來達(dá)到這個(gè)目的。
4)如果一個(gè)類成員不是不可變量,那么在成員初始化或者使用get方法獲取該成員變量時(shí),需要通過clone方法來確保類的不可變性。
5)如果有必要,可使用覆蓋Object類的equals()方法和hashCode()方法。在equals()方法中,根據(jù)對(duì)象的屬性值來比較兩個(gè)對(duì)象是否相等,并且保證用equals()方法判斷為相等的兩個(gè)對(duì)象的hashCode()方法的返回值也相等,這可以保證這些對(duì)象能被正確地放到HashMap或HashSet集合中。
除此之外,還有一些小的注意事項(xiàng):由于類的不可變性,在創(chuàng)建對(duì)象時(shí)就需要初始化所有成員變量,因此最好提供一個(gè)帶參數(shù)的構(gòu)造函數(shù)來初始化這些成員變量。
下面通過給出一個(gè)錯(cuò)誤的實(shí)現(xiàn)方法與一個(gè)正確的實(shí)現(xiàn)方法來說明在實(shí)現(xiàn)這種類時(shí)需要特別注意的問題。首先給出一個(gè)錯(cuò)誤的實(shí)現(xiàn)方法:
importjava.util.Date;
classImmutableClass{
privateDated;
publicImmutableClass(Dated){
this.d=d;
}
publicvoidprintState(){
System.out.println(d);
}
}
publicclassTestImmutable{
publicstaticvoidmain(String[]args){
Dated=newDate();
ImmutableClassimmuC=newImmutableClass(d);
immuC.printState();
d.setMonth(5);
immuC.printState();
}
程序運(yùn)行結(jié)果為:
SunAug0417:41:47CST2013
TueJun0417:41:47CST2013
需要說明的是,由于Date對(duì)象的狀態(tài)是可以被改變的,而ImmutableClass保存了Date類型對(duì)象的引用,當(dāng)被引用的對(duì)象的狀態(tài)改變時(shí)會(huì)導(dǎo)致ImmutableClass對(duì)象狀態(tài)的改變。
其實(shí),正確的實(shí)現(xiàn)方法如下所示:
importjava.util.ArrayList;
import.java.util.Date;
classImmutableClass{
privateDated;
publicImmutableClass(Dated){
this.d=(Date)d.clone();//解除了引用關(guān)系
}
publicvoidprintState(){
System.out.println(d);
}
publicDategetDate(){
return(Date)d.clone();
}
}
publicclassTest{
publicstaticvoidmain(String[]args){
Dated=newDate();
ImmutableClassimmuC=newImmutableClass(d);
immuC.printState();
d.setMonth(5);
immuC.printState();
}
}
程序運(yùn)行結(jié)果為:
SunAug0417:47:03CST2013
SunAug0417:47:03CST2013
Java語言中之所以設(shè)計(jì)有很多不可變類,主要是不可變類具有使用簡單、線程安全、節(jié)省內(nèi)存等優(yōu)點(diǎn),但凡事有利就有弊,不可變類自然也有其缺點(diǎn),例如,不可變類的對(duì)象會(huì)因?yàn)橹档牟煌a(chǎn)生新的對(duì)象,從而導(dǎo)致無法預(yù)料的問題,所以,切不可濫用這種模式。
11.
值傳遞與引用傳遞有哪區(qū)別正確答案:方法調(diào)用是編程語言中非常重要的一個(gè)特性,在方法調(diào)用時(shí),通常需要傳遞一些參數(shù)來完成特定的功能。Java語言提供了兩種參數(shù)傳遞的方式:值傳遞和引用傳遞。
(1)值傳遞
在方法調(diào)用中,實(shí)參會(huì)把它的值傳遞給形參,形參只是用實(shí)參的值初始化一個(gè)臨時(shí)的存儲(chǔ)單元,因此形參與實(shí)參雖然有著相同的值,但是卻有著不同的存儲(chǔ)單元,因此對(duì)形參的改變不會(huì)影響實(shí)參的值。
(2)引用傳遞
在方法調(diào)用中,傳遞的是對(duì)象(也可以看作是對(duì)象的地址),這時(shí)形參與實(shí)參的對(duì)象指向同一塊存儲(chǔ)單元,因此對(duì)形參的修改就會(huì)影響實(shí)參的值。
在Java語言中,原始數(shù)據(jù)類型在傳遞參數(shù)時(shí)都是按值傳遞,而包裝類型在傳遞參數(shù)時(shí)是按引用傳遞的。
下面通過一個(gè)例子來介紹按值傳遞和按引用傳遞的區(qū)別:
publicclassTest{
publicstaticvoidtestPassParameter(StringBuffterss1,intn){
ss1.append("World");//引用
n=8;//值
}
publicstaticvoidmain(String[]args){
inti=1;
StringBuffers1=newStringBuffer("Hello");
testPassParameter(s1,i);
System.out.println(s1);
System.out.println(i);
}
}
程序運(yùn)行結(jié)果為:
HelloWorld
1
按引用傳遞其實(shí)與傳遞指針類似,是把對(duì)象的地址作為參數(shù)的,如下圖所示。
為了便于理解,假設(shè)1和“Hello”存儲(chǔ)的地址分別為0X12345678和0XFFFFFF12。在調(diào)用方法testPassParameter時(shí),由于i為基本類型,因此參數(shù)是按值傳遞的,此時(shí)會(huì)創(chuàng)建一個(gè)i的副本,該副本與i有相同的值,把這個(gè)副本作為參數(shù)賦值給n,作為傳遞的參數(shù)。而StringBuffer由于是一個(gè)類,因此按引用傳遞,傳遞的是它的引用(傳遞的是存儲(chǔ)“Hello的地址”),如圖所示,在testPassParameter內(nèi)部修改的是n的值,這個(gè)值與i是沒關(guān)系的。但是在修改ss1時(shí),修改的是ss1這個(gè)地址指向的字符串,由于形參ss1與實(shí)參s1指向的是同一塊存儲(chǔ)空間,因此修改ss1后,s1指向的字符串也被修改了。
Java中處理8種基本的數(shù)據(jù)類型用的是值傳遞,其他所有類型都用的是引用傳遞,由于這8種基本數(shù)據(jù)類型的包裝類型都是不可變量,因此增加了對(duì)“按引用傳遞”的理解難度。下面給出一個(gè)示例來說明:
publicclassTest{
publicstaticvoidchangeStringBuffer(StringBufferss1,StringBufferss2){
ss1.append("World");
ss2=ss1;
}
publicstaticvoidmain(String[]args){
Integera=1;
Integerb=a;
b++;
System.out.println(a);
System.out.println(b);
StringBuffers1=newStringBuffer("Hello");
StringBuffers2=newStringBuffer("Hello");
changeStfingBuffer(s1,s2);
System.out.println(s1);
System.out.println(s2);
}
程序運(yùn)行結(jié)果為:
1
2
HelloWorld
Hello
對(duì)于上述程序的前兩個(gè)輸出“1”和“2”,不少讀者可能會(huì)認(rèn)為,Integer是按值傳遞的而不是按引用傳遞的,其實(shí)這是一個(gè)理解上的誤區(qū),上述代碼還是按引用傳遞的,只是由于Integer是不可變類,因此沒有提供改變它值的方法,在上例中,在執(zhí)行完語句b++后,由于Integer是不可變類,因此此時(shí)會(huì)創(chuàng)建一個(gè)新值為2的Integer賦值給b,此時(shí)b與a其實(shí)已經(jīng)沒有任何關(guān)系了。
下面通過程序的后兩個(gè)輸出來加深對(duì)“按引用傳遞”的理解。為了理解后兩個(gè)輸出結(jié)果,首先必須理解“引用也是按值傳遞的”這一要點(diǎn)。為了便于理解,假設(shè)s1和s2指向字符串的地址分別為0X12345678和0XFFFFFF12,那么在調(diào)用函數(shù)changeStringBuffer時(shí),傳遞s1與s2的引用就可以理解為傳遞了兩個(gè)地址0X12345678和0XFFFFFF12,而且這兩個(gè)地址是按值傳遞的(即傳遞了兩個(gè)值,ss1為0X12345678,ss2為0XFFFFFF12),在調(diào)用方法ss1.append("World")時(shí),會(huì)修改ss1所指向的字符串的值,因此會(huì)修改調(diào)用者的s1的值,得到的輸出結(jié)果為“HelloWorld”。但是在執(zhí)行ss2=ss1時(shí),只會(huì)修改ss2的值而對(duì)s2毫無影響,因此s2的值在調(diào)用前后保持不變。為了便于理解,下圖給出了函數(shù)調(diào)用的處理過程。
從圖中可以看出,在傳遞參數(shù)時(shí)相當(dāng)于傳遞了兩個(gè)地址,在調(diào)用ss1.append("World")時(shí),修改了這個(gè)地址所指向字符串的值,而在調(diào)用ss2=ss1時(shí),相當(dāng)于修改了函數(shù)changeStringBuffer內(nèi)部的局部變量ss2,這個(gè)修改與ss1沒關(guān)系。
常見筆試題:
下列說法中,正確的是______。
A.callbyvalue不會(huì)改變實(shí)際參數(shù)的值
B.callbyreference能改變實(shí)際參數(shù)
C.callbyreference不能改變實(shí)際參數(shù)的地址
D.callbyreference能改變實(shí)際參數(shù)的內(nèi)容
答案:A、C、D。見上面講解。
12.
不同數(shù)據(jù)類型的轉(zhuǎn)換有哪規(guī)則正確答案:在Java語言中,當(dāng)參與運(yùn)算的兩個(gè)變量的數(shù)據(jù)類型不同時(shí),就需要進(jìn)行隱式的數(shù)據(jù)類型轉(zhuǎn)換,轉(zhuǎn)換的規(guī)則為:從低精度向高精度轉(zhuǎn)換,即優(yōu)先級(jí)滿足byte<short<char<int<long<float<double,例如,不同數(shù)據(jù)類型的值在進(jìn)行運(yùn)算時(shí),short類型數(shù)據(jù)能夠自動(dòng)轉(zhuǎn)為int類型,int類型數(shù)據(jù)能夠自動(dòng)轉(zhuǎn)換為float類型等。反之,則需要通過強(qiáng)制類型轉(zhuǎn)換來實(shí)現(xiàn)。
在Java語言中,類型轉(zhuǎn)換可以分為以下幾種類型:
(1)類型自動(dòng)轉(zhuǎn)換
低級(jí)數(shù)據(jù)類型可以自動(dòng)轉(zhuǎn)換為高級(jí)數(shù)據(jù)類型,下表給出了常見的自動(dòng)類型轉(zhuǎn)換的規(guī)則。自動(dòng)類型轉(zhuǎn)換的規(guī)則操作數(shù)1的類型操作數(shù)2的類型轉(zhuǎn)換后的類型longbyteshortcharintlongintbyteshortcharintfloatbyteshortintcharlongfloatdoublebyteshortintlongcharfloatdouble當(dāng)類型自動(dòng)轉(zhuǎn)換時(shí),需要注意以下幾點(diǎn):1)char類型的數(shù)據(jù)轉(zhuǎn)換為高級(jí)類型(如int,long等),會(huì)轉(zhuǎn)換為其對(duì)應(yīng)的ASCII碼。2)byte、char、short類型的數(shù)據(jù)在參與運(yùn)算時(shí)會(huì)自動(dòng)轉(zhuǎn)換為int型,但當(dāng)使用“+=”運(yùn)算時(shí),就不會(huì)產(chǎn)生類型的轉(zhuǎn)換(將在下一節(jié)中詳細(xì)介紹)。3)另外,在Java語言中,基本數(shù)據(jù)類型與boolean類型是不能相互轉(zhuǎn)換的??傊?dāng)有多種類型的數(shù)據(jù)混合運(yùn)算時(shí),系統(tǒng)會(huì)先自動(dòng)地將所有數(shù)據(jù)轉(zhuǎn)換成容量最大的那一種數(shù)據(jù)類型,然后再進(jìn)行計(jì)算。(2)強(qiáng)制類型轉(zhuǎn)換當(dāng)需要從高級(jí)數(shù)據(jù)類型轉(zhuǎn)換為低級(jí)數(shù)據(jù)類型時(shí),就需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,下表給出了強(qiáng)制類型轉(zhuǎn)換的規(guī)則。強(qiáng)制類型轉(zhuǎn)換的規(guī)則原操作數(shù)的類型轉(zhuǎn)換后操作數(shù)的類型bytecharcharbytecharshortbytecharintbyteshortcharlongbyteshortcharintfloatbyteshortcharintlongdoublebyteshortcharintlongdouble
需要注意的是,在進(jìn)行強(qiáng)制類型轉(zhuǎn)換時(shí)可能會(huì)損失精度。
常見筆試題:
1.下面程序的運(yùn)行結(jié)果是什么?
inti=1;
if(i)
System.out.println("true");
else
System.out.println("false");
答案:編譯錯(cuò)誤。因?yàn)閕f條件只接受boolean類型的值(true或false),而i的類型為int,int類型不能被隱式地轉(zhuǎn)換為boolean類型。
2.對(duì)于下述代碼結(jié)果強(qiáng)制類型轉(zhuǎn)換后,變量a和b的值分別為______。
shorta=128;
byteb=(byte)a
答案:a=128,b=-128。short類型變量占兩個(gè)字節(jié),a對(duì)應(yīng)的二進(jìn)制為:0000000010000000,由于byte只占一個(gè)字節(jié),在強(qiáng)制轉(zhuǎn)換為byte的時(shí)候只截取低字節(jié):10000000,10000000是-128的補(bǔ)碼,因此b的值為-128。
13.
強(qiáng)制類型轉(zhuǎn)換的注意事項(xiàng)有哪正確答案:Java語言在涉及byte、short和char類型的運(yùn)算時(shí),首先會(huì)把這些類型的變量值強(qiáng)制轉(zhuǎn)換為int類型,然后對(duì)int類型的值進(jìn)行計(jì)算,最后得到的值也是int類型。因此,如果把兩個(gè)short類型的值相加,最后得到的結(jié)果是int類型;如果把兩個(gè)byte類型的值相加,最后也會(huì)得到一個(gè)int類型的值。如果需要得到short類型的結(jié)果,就必須顯式地把運(yùn)算結(jié)果轉(zhuǎn)換為short類型,例如對(duì)于語句shorts1=1;s1=s1+1,由于在運(yùn)行時(shí)會(huì)首先將s1轉(zhuǎn)換成int類型,因此s1+1的結(jié)果為int類型,這樣編譯器會(huì)報(bào)錯(cuò),所以,正確的寫法應(yīng)該shorts1=1;s1=(short)(s1+1)。
有一種例外情況?!?=”為Java語言規(guī)定的運(yùn)算法,Java編譯器會(huì)對(duì)其進(jìn)行特殊處理,因此,語句shorts1=1;s1+=1能夠編譯通過。
14.
運(yùn)算符優(yōu)先級(jí)是什么正確答案:Java語言中有很多運(yùn)算符,由于運(yùn)算符優(yōu)先級(jí)的問題經(jīng)常會(huì)導(dǎo)致程序出現(xiàn)意想不到的結(jié)果,下表詳細(xì)介紹了運(yùn)算符的優(yōu)先級(jí)。運(yùn)算符的優(yōu)先級(jí)優(yōu)先級(jí)運(yùn)算符結(jié)合性1.()[]從左向右2+(正)-(負(fù))++--~!3*/%4+(加)-(減)5<<>>(無符號(hào)右移)>>>(有符號(hào)右移)6<<=>>=instanceof7==!=8&9|10^11&&12||13?:14=
+=-=*=/=%=&==|=^=~=<<=>>=>>>=
在實(shí)際使用時(shí),如果不確定運(yùn)算符的優(yōu)先級(jí),最好運(yùn)用括號(hào)運(yùn)算符來控制運(yùn)算順序。
常見筆試題:
下面程序的運(yùn)行結(jié)果是什么?
publicclassTest{
publicstaticvoidmain(String[]args){
bytea=5;
intb=10;
intc=a>>2+b>>2;
System.out.println(c);
}
}
答案:0。由于“+”的優(yōu)先級(jí)比“>>”高,因此程序中的表達(dá)式等價(jià)于a>>(2+b)>>2,相當(dāng)于a>>12>>2,因此運(yùn)行結(jié)果為0。
15.
Math類中round、ceil和floor方法的功能各是什么正確答案:round、ceil和floor方法位于Math類中,Math是一個(gè)包含了很多數(shù)學(xué)常量與計(jì)算方法的類,位于java.lang包下,能自動(dòng)導(dǎo)入,而且Math類里邊的方法全是靜態(tài)方法。下面重點(diǎn)介紹這3個(gè)方法代表的含義。
1)round方法表示四舍五入。round,意為“環(huán)繞”,其實(shí)現(xiàn)原理是在原來數(shù)字的基礎(chǔ)上先增加0.5然后再向下取整,等同于(int)Math.floor(x+0.5f)。它的返回值類型為int型,例如,Math.round(11.5)的結(jié)果為12,Math.round(-11.5)的結(jié)果為-11。
2)ceil方法的功能是向上取整。ceil,意為“天花板”,顧名思義是對(duì)操作數(shù)取頂,Math.ceil(a),就是取大于a的最小的整數(shù)值。需要注意的是,它的返回值類型并不是int型,而是double型。若a是正數(shù),則把小數(shù)“入”,若a是負(fù)數(shù),則把小數(shù)“舍”。
3)floor方法的功能是向下取整。floor,意為“地板”,顧名思義是對(duì)操作數(shù)取底。Math.floor(a),就是取小于a的最大的整數(shù)值。它的返回值類型與ceil方法一樣,也是double型。若a是正數(shù),則把小數(shù)“舍”;若a是負(fù)數(shù),則把小數(shù)“入”。
下表是一個(gè)實(shí)例分析。floor、round與ceil的區(qū)別數(shù)字Math.floor方法Math.round方法Math.ceil方法1.41.012.01.51.022.01.61.022.0-1.4-2.0-1-1.0-1.5-2.0-1-1.0-1.6-2.0-2-1.0
以下是一段測(cè)試代碼:
classMathTest{
publicstaticvoidmain(String[]args){
floatm=6.4f;
floatn=-6.4f;
System.out.println("Math.round("+m+")="+Math.round(m));
System.out.println("Math.round("+n+")="+Math.round(n));
System.out.println("Math.ceil("+m+")="+Math.ceil(m));
System.out.println("Math.ceil("+n+")="+Math.ceil(n));
System.out.println("Math.floor("+m+")="+Math.floor(m));
System.out.println("Math.floor("+n+")="+Math.floor(n));
}
}
上例的運(yùn)行結(jié)果為:
Math.round(6.4)=6
Math.round(-6.4)=-6
Math.ceil(6.4)=7.0
Math.ceil(-6.4)=-6.0
Math.floor(6.4)=6.0
Math.floor(-6.4)=-7.0
常見筆試題:
Math.round(11.5)等于多少?Math.round(-11.5)等于多少?
答案:12,-11。見上面講解。
16.
++i與i++有什么區(qū)別正確答案:在編程時(shí),經(jīng)常會(huì)用到變量的自增或自減操作,尤其在循環(huán)中用得最多。以自增為例,有兩種自增方式:前置與后置,即++i和i++,它們的不同點(diǎn)在于i++是在程序執(zhí)行完畢后進(jìn)行自增,而++i是在程序開始執(zhí)行前進(jìn)行自增,示例如下:
publicclassTest{
publicstaticvoidmain(String[]a){
inti=1;
System.out.println(i+++i++);
System.out.println("i="+i);
System.out.println(i+++++i);
System.out.println("i="+i);
System.out.println(i+++i+++i++);
System.out.println("i="+i);
}
}
程序運(yùn)行結(jié)果為:
3
i=3
8
i=5
18
i=8
上例中的程序運(yùn)行結(jié)果讓很多讀者感到困惑不解,其實(shí)稍作分析,問題便迎刃而解了。表達(dá)式i+++i++首先執(zhí)行第一個(gè)i++操作,由于自增操作會(huì)稍后執(zhí)行,因此,運(yùn)算時(shí)i的值還是1,但自增操作后,i的值變?yōu)榱?,接著執(zhí)行第二個(gè)i++,運(yùn)算時(shí),i的值已經(jīng)為2了,而執(zhí)行了一個(gè)自增操作后,i的值變?yōu)榱?,所以i+++i++=1+2=3,而運(yùn)算完成后,i的值變?yōu)?。
表達(dá)式i+++++i首先執(zhí)行第一個(gè)i++,但是自增操作會(huì)稍后執(zhí)行。因此,此時(shí)i的值還是3,接著執(zhí)行++i,此時(shí)i的值變?yōu)?,同時(shí)還要補(bǔ)執(zhí)行i++的自增操作,因此此時(shí)i的值變?yōu)?,所以i+++++i=3+5=8。
同理,i+++i+++i++=5+6+7=18。
常見筆試題:
假設(shè)x=1,y=2,z=3,則表達(dá)式y(tǒng)+=z--/++x的值是______。
A.3
B.3.5
C.4
D.5
答案:A。見上面講解。
17.
如何實(shí)現(xiàn)無符號(hào)數(shù)的右移操作正確答案:Java提供了兩種右移運(yùn)算符:“>>”和“>>>”。其中,“>>”被稱為有符號(hào)右移運(yùn)算符,“>>>”被稱為無符號(hào)右移運(yùn)算符,它們的功能是將參與運(yùn)算的對(duì)象對(duì)應(yīng)的二進(jìn)制數(shù)右移指定的位數(shù)。二者的不同點(diǎn)在于“>>”在執(zhí)行右移操作時(shí),若參與運(yùn)算的數(shù)字為正數(shù),則在高位補(bǔ)0;若為負(fù)數(shù),則在高位補(bǔ)1。而“>>>”則不同,無論參與運(yùn)算的數(shù)字為正數(shù)或?yàn)樨?fù)數(shù),在執(zhí)行運(yùn)算時(shí),都會(huì)在高位補(bǔ)0。
此外,需要特別注意的是,在對(duì)char、byte、short等類型的數(shù)進(jìn)行移位操作前,編譯器都會(huì)自動(dòng)地將數(shù)值轉(zhuǎn)化為int類型,然后才進(jìn)行移位操作。由于int型變量只占4Byte(32bit),因此當(dāng)右移的位數(shù)超過32bit時(shí),移位運(yùn)算沒有任何意義。所以,在Java語言中,為了保證移動(dòng)位數(shù)的有效性,以使右移的位數(shù)不超過32bit,采用了取余的操作,即a>>n等價(jià)于a>>(n%32),示例如下:
publicclassTest{
publicstaticvoidmain(String[]a){
inti=-4;
System.out.println("-----int>>:"+i);
System.out.println("移位前二進(jìn)制:"+Integer.toBinaryString(i));
i>>=1;
System.out.println("移位后二進(jìn)制:"+Integer.toBinaryString(i));
System.out.println("-----int>>:"+i);
i=-4;
System.out.println("------int>>>”+i);
System.out.println("移位前二進(jìn)制:"+Integer.toBinaryString(i));
i>>>=1;
System.out.println("移位后二進(jìn)制:"+Integer.toBinaryString(i));
System.out.println("-----int>>>:"+i);
shortj=-4;
System.out.println("-----short>>>:"+J);
System.out.println(”移位前二進(jìn)制:"+Integer.toBinaryString(j));
j>>>=1;
System.out.println("移位后二進(jìn)制:"+Integer.toBinaryString(j));
System.out.println("-----short>>>:"+j);
i=5;
System.out.println("-----int>>:"+i);
System.out.println("位前二進(jìn)制:"+Integer.toBinaryString(i));
i>>=32;
System.out.println("移位后二進(jìn)制:"+Integer.toBinaryString(i));
System.out.println("------int>>:“+i);
}
}
程序運(yùn)行結(jié)果為:
-----int>>:-4
移位前二進(jìn)制:11111111111111111111111111111100
移位后二進(jìn)制:11111111111111111111111111111110
-----int>>:-2
-----int>>>:-4
移位前二進(jìn)制:11111111111111111111111111111100
移位后二進(jìn)制:1111111111111111111111111111110
-----int>>>:2147483646
-----short>>>:-4
移位前二進(jìn)制:11111111111111111111111111111100
移位后二進(jìn)制:11111111111111111111111111111110
-----short>>>:-2
-----int>>:5
移位前二進(jìn)制:101
移位后二進(jìn)制:101
-----int>>:5
需要特別說明的是,對(duì)于short類型來說,由于short只占2Byte,在移位操作時(shí)會(huì)先轉(zhuǎn)換為int類型,雖然在進(jìn)行無符號(hào)右移時(shí)會(huì)在高位補(bǔ)1,但當(dāng)把運(yùn)算結(jié)果再賦值給short類型變量時(shí),只會(huì)取其中低位的兩個(gè)字節(jié),因此,高位無論補(bǔ)0還是補(bǔ)1對(duì)運(yùn)算結(jié)果無影響。在上例中,-4的二進(jìn)制
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度影視基地場(chǎng)地及道具租賃合同4篇
- 二零二五版智能家電組裝加工承包合作協(xié)議2篇
- 二零二五年度森林防火鏟車租賃及應(yīng)急救援協(xié)議3篇
- 二零二五年度股東股權(quán)轉(zhuǎn)讓他益權(quán)與公司分紅調(diào)整合同3篇
- 二零二五版市場(chǎng)營銷咨詢與服務(wù)合同3篇
- 二零二五年度綠色制造車間生產(chǎn)承包合作協(xié)議書3篇
- 2025屆山西?。ㄟ\(yùn)城地區(qū))達(dá)標(biāo)名校中考生物猜題卷含解析
- 二零二四年小麥種子區(qū)域化種植推廣購銷協(xié)議3篇
- 醇沉課程設(shè)計(jì)
- 2025年度鋁合金裝飾面板加工與銷售合同4篇
- 安徽省合肥市2023-2024學(xué)年七年級(jí)上學(xué)期期末數(shù)學(xué)試題(含答案)
- 2025年高考化學(xué)試題分析及復(fù)習(xí)策略講座
- 合同債務(wù)人變更協(xié)議書模板
- 2024年高中生物新教材同步選擇性必修第三冊(cè)學(xué)習(xí)筆記第4章 本章知識(shí)網(wǎng)絡(luò)
- 西班牙可再生能源行業(yè)市場(chǎng)前景及投資研究報(bào)告-培訓(xùn)課件外文版2024.6光伏儲(chǔ)能風(fēng)電
- 2024-2029年中國制漿系統(tǒng)行業(yè)市場(chǎng)現(xiàn)狀分析及競(jìng)爭格局與投資發(fā)展研究報(bào)告
- 大門封條模板
- (正式版)SHT 3225-2024 石油化工安全儀表系統(tǒng)安全完整性等級(jí)設(shè)計(jì)規(guī)范
- 《輸變電工程三維協(xié)同設(shè)計(jì)規(guī)范》
- 2024年中國工商銀行寧波市分行招聘筆試參考題庫附帶答案詳解
- 兒童醫(yī)院禮儀培訓(xùn)課件
評(píng)論
0/150
提交評(píng)論