Java程序員面試分類模擬9_第1頁
Java程序員面試分類模擬9_第2頁
Java程序員面試分類模擬9_第3頁
Java程序員面試分類模擬9_第4頁
Java程序員面試分類模擬9_第5頁
已閱讀5頁,還剩33頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

Java程序員面試分類模擬9論述題1.

Java語言有哪優(yōu)點正確答案:SunMicrosystems公司對Java語言的描述如下:“Javaisasimple,object-orien(江南博哥)ted,distributed,interpreted,robust,secure,architectureneutral,portable,high-performance,multithreaded,anddynamiclanguage”。具體而言,Java語言具有以下幾個方面的優(yōu)點:

1)Java為純面向對象的語言?!禞ava編程思想》提到Java語言是一種“Everythingisobject”的語言,它能夠直接反應現(xiàn)實生活中的對象,例如火車、動物等,因此通過它,開發(fā)人員編寫程序更為容易。

2)平臺無關性。Java語言可以“一次編譯,到處運行”。無論是在windows平臺還是在Linux、MacOS等其他平臺上對Java程序進行編譯,編譯后的程序在其他平臺上都可以運行。由于Java為解釋型語言,編譯器會把Java代碼變成“中間代碼”,然后在Java虛擬機(JavavirtualMachine,JVM)上解釋執(zhí)行。由于中間代碼與平臺無關,因此,Java語言可以很好地跨平臺執(zhí)行,具有很好的可移植性。

3)Java提供了很多內(nèi)置的類庫,通過這些類庫,簡化了開發(fā)人員的程序設計工作,同時縮短了項目的開發(fā)時間,例如,Java語言提供了對多線程的支持,提供了對網(wǎng)絡通信的支持,最重要的是提供了垃圾回收器,這使得開發(fā)人員從對內(nèi)存的管理中解脫出來。

4)提供了對Web應用開發(fā)的支持,例如,Applet、Servlet和JSP可以用來開發(fā)Web應用程序;Socket、RMI可以用來開發(fā)分布式應用程序的類庫。

5)具有較好的安全性和健壯性。Java語言經(jīng)常被用在網(wǎng)絡環(huán)境中,為了增強程序的安全性,Java語言提供了一個防止惡意代碼攻擊的安全機制(數(shù)組邊界檢測和Bytecode校驗等)。Java的強類型機制、垃圾回收器、異常處理和安全檢查機制使得用Java語言編寫的程序有很好的健壯性。

6)去除了C++語言中難以理解、容易混淆的特性,例如頭文件、指針、結構、單元、運算符重載、虛擬基礎類、多重繼承等,使得程序更加嚴謹、簡潔。

常見筆試題:

Java語言是由______語言改進并重新設計而來的。

A.Ada

B.C++

C.Pascal

D.BASIC

答案:B。Ada語言是美國軍方為了整合不同語言開發(fā)的系統(tǒng)而發(fā)明的一種語言,其最大的特點是實時性,在Ada95中已加入面向對象內(nèi)容。Pascal語言是為提倡結構化編程而發(fā)明的語言。BASIC語言為了讓大學生容易地控制計算機開發(fā)的語言,其特點是簡單易懂,且可以用解釋和編譯兩種方法執(zhí)行。C++語言是一種靜態(tài)數(shù)據(jù)類型檢查的、支持多重編程范式的通用程序設計語言,它支持過程化程序設計、數(shù)據(jù)抽象、面向對象程序設計、泛型程序設計等多種程序設計風格。Java語言是一種面向對象語言,從語法結構上看,與C++類似。

2.

Java與C/C++有什么異同正確答案:Java與C++都是面向對象語言,都使用了面向對象思想(例如封裝、繼承、多態(tài)等),由于面向對象有許多非常好的特性(繼承、組合等),因此二者都有很好的可重用性。

需要注意的是,二者并非完全一樣,下面主要介紹它們的不同點:

1).Java為解釋性語言,其運行過程為:程序源代碼經(jīng)過Java編譯器編譯成字節(jié)碼,然后由JVM解釋執(zhí)行。而C/C++為編譯型語言,源代碼經(jīng)過編譯和鏈接后生成可執(zhí)行的二進制代碼。因此,Java的執(zhí)行速度比C/C++慢,但是Java能夠跨平臺執(zhí)行,而C/C++不能。

2)Java為純面向對象語言,所有代碼(包括函數(shù)、變量等)必須在類中實現(xiàn),除基本數(shù)據(jù)類型(包括int、float等)外,所有類型都是類。此外,Java語言中不存在全局變量或全局函數(shù),而C++兼具面向過程和面向過程編程的特點,可以定義全局變量和全局函數(shù)。

3)與C/C++語言相比,Java語言中沒有指針的概念,這有效防止了C/C++語言中操作指針可能引起的系統(tǒng)問題,從而使程序變得更加安全。

4)與C++語言相比,Java語言不支持多重繼承,但是Java語言引入了接口的概念,可以同時實現(xiàn)多個接口。由于接口也具有多態(tài)特性,因此在Java語言中可以通過實現(xiàn)多個接口來實現(xiàn)與C++語言中多重繼承類似的目的。

5)在C++語言中,需要開發(fā)人員去管理對內(nèi)存的分配(包括申請與釋放),而Java語言提供了垃圾回收器來實現(xiàn)垃圾的自動回收,不需要程序顯式地管理內(nèi)存的分配。在C++語言中,通常都會把釋放資源的代碼放到析構函數(shù)中,Java語言中雖然沒有析構函數(shù),但卻引入了一個finalize()方法,當垃圾回收器將要釋放無用對象的內(nèi)存時,會首先調(diào)用該對象的finalize()方法,因此,開發(fā)人員不需要關心也不需要知道對象所占的內(nèi)存空間何時會被釋放。

C++語言支持運算符重載,而Java語言不支持運算符重載。C++語言支持預處理,而Java語言沒有預處理器,雖然不支持預處理功能(包括頭文件、宏定義等),但它提供的import機制與C++中的預處理器功能類似。C++支持默認函數(shù)參數(shù),而Java不支持默認函數(shù)參數(shù)。C/C++支持goto語句,而Java不提供goto語句(但Java中goto是保留關鍵字)。C/C++支持自動強制類型轉換,這會導致程序的不安全;而Java不支持自動強制類型轉換,必須由開發(fā)人員進行顯式地強制類型轉換。C/C++中,結構和聯(lián)合的所有成員均為公有,這往往會導致安全性問題的發(fā)生,而Java根本就不包含結構和聯(lián)合,所有內(nèi)容都封裝在類里面。

Java具有平臺無關性,即對每種數(shù)據(jù)類型都分配固定長度,例如,int類型總是占據(jù)32位,而C/C++卻不然,同一個數(shù)據(jù)類型在不同的平臺上會分配不同的字節(jié)數(shù)。

Java提供對注釋文檔的內(nèi)建支持,所以源碼文件也可以包含它們自己的文檔。通過一個單獨的程序,這些文檔信息可以提取出來,并重新格式化成HTML。

Java包含了一些標準庫,用于完成特定的任務,同時這些庫簡單易用,能夠大大縮短開發(fā)周期,例如,Java提供了用于訪問數(shù)據(jù)庫的JDBC庫,用于實現(xiàn)分布式對象的RMI等標準庫。C++則依靠一些非標準的、由其他廠商提供的庫。

常見筆試題:

下列說法中,錯誤的有______。

A.Java面向對象語言容許單獨的過程與函數(shù)存在

B.Java面向對象語言容許單獨的方法存在

C.Java語言中的方法屬于類中的成員(member)

D.Java語言中的方法必定隸屬于某一類(對象),調(diào)用方法與過程或函數(shù)相同

答案:A、B、C。見上面講解。

3.

為什么需要publicstaticvoidmain(String[]args)這個方法正確答案:publicstaticvoidmain(String[]args)為Java程序的入口方法,JVM在運行程序時,會首先查找main()方法。其中,public是權限修飾符,表明任何類或對象都可以訪問這個方法,static表明main()方法是一個靜態(tài)方法,即方法中的代碼是存儲在靜態(tài)存儲區(qū)的,只要類被加載后,就可以使用該方法而不需要通過實例化對象來訪問,可以直接通過類名.main()直接訪問,JVM在啟動時就是按照上述方法的簽名(必須有public與static修飾,返回值為void,且方法的參數(shù)為字符串數(shù)組)來查找方法的入口地址,若能找到,就執(zhí)行;找不到,則會報錯。void表明方法沒有返回值,main是JVM識別的特殊方法名,是程序的入口方法。字符串數(shù)組參數(shù)args為開發(fā)人員在命令行狀態(tài)下與程序交互提供了一種手段。

因為main是程序的入口方法,所以當程序運行時,第一個執(zhí)行的方法就是main()方法。通常來講,要執(zhí)行一個類的方法,先必須實例化一個類的對象,然后通過對象來調(diào)用這個方法。但由于main是程序的入口方法,此時還沒有實例化對象,因此在編寫main()方法時就要求不需要實例化對象就可以調(diào)用這個方法,鑒于此,main()方法需要被定義成public與static。下例給出了在調(diào)用main()方法時傳遞參數(shù)的方法。

publicclassTest{

publicstaticvoidmain(String[]args){

for(inti=0;i<args.length;i++){

System.out.println(args[i]);

}

}

}

在控制臺下,使用javacTestjava指令編譯上述程序,使用javaTestarg1arg2arg3指令運行程序,程序運行結果為:

arg1

arg2

arg3

引申:

1.main()方法是否還有其他可用的定義格式?

1)由于public與static沒有先后順序關系,因此下面的定義也是合理的。

staticpublicvoidmain(String[]args)

2)也可以把main()方法定義為final。

publicstaticfinalvoidmain(String[]args)

3)也可以用synchronized來修飾main()方法。

staticpublicsynchronizedvoidmain(String[]args)

不管哪種定義方式,都必須保證main()方法的返回值為void,并有static與public關鍵字修飾。同時由于main()方法為程序的入口方法,因此不能用abstract關鍵字來修飾。

2.同一個java文件中是否可以有多個main()方法?

雖然每個類中都可以定義main()方法,但是只有與文件名相同的用public修飾的類中的main()方法才能作為整個程序的入口方法。如下例所示,創(chuàng)建了一個名為Test.java的文件。

classT{

publicstaticvoidmain(String[]args){

System.out.println("Tmain");

}

}

publicclassTest{

//程序入口函數(shù)

publicstaticvoidmain(String[]args){

System.out.println("Testmain");

}

}

程序運行結果為:

Testmain

常見筆試題:

Java程序中程序運行入口方法main的簽名正確的有______。

A.publicstaticvoidmain(String[]args)

B.publicstaticfinalvoidmain(String[]args)

C.staticpublicvoidmain(String[]args)

D.staticpublicsynchronizedvoidmain(String[]args)

E.staticpublicabstractvoidmain(String[]args)

答案:A、B、C、D。見上面講解。

4.

如何實現(xiàn)在main()方法執(zhí)行前輸出“HelloWorld”正確答案:眾所周知,在Java語言中,main()方法是程序的入口方法,在程序運行時,最先加載的就是main()方法,但這是否意味著main()方法就是程序運行時第一個被執(zhí)行的模塊呢?

答案是否定的。在Java語言中,由于靜態(tài)塊在類被加載時就會被調(diào)用,因此可以在main()方法執(zhí)行前,利用靜態(tài)塊實現(xiàn)輸出“HelloWorld”的功能,以如下代碼為例。

publicclassTest{

static{

System.out.println("HelloWorld1");

}

publicstaticvoidmain(Stringargs[]){

System.out.println("HelloWorld2");

}

}

程序運行結果為:

HelloWorld1

HelloWorld2

由于靜態(tài)塊不管順序如何,都會在main()方法執(zhí)行之前執(zhí)行,因此,以下代碼會與上面的代碼有同樣的輸出結果。

publicclassTest{

publicstaticvoidmain(Stringargs[]){

System.out.println("HelloWorld2");

}

static{

system.out.println("HelloWorld1”);

}

}

5.

Java程序初始化的順序是怎樣的正確答案:在Java語言中,當實例化對象時,對象所在類的所有成員變量首先要進行初始化,只有當所有類成員完成初始化后,才會調(diào)用對象所在類的構造函數(shù)創(chuàng)建對象。

Java程序的初始化一般遵循3個原則(優(yōu)先級依次遞減):①靜態(tài)對象(變量)優(yōu)先于非靜態(tài)對象(變量)初始化,其中,靜態(tài)對象(變量)只初始化一次,而非靜態(tài)對象(變量)可能會初始化多次。②父類優(yōu)先于子類進行初始化。③按照成員變量的定義順序進行初始化。即使變量定義散布于方法定義之中,它們依然在任何方法(包括構造函數(shù))被調(diào)用之前先初始化。

Java程序初始化工作可以在許多不同的代碼塊中來完成(例如靜態(tài)代碼塊、構造函數(shù)等),它們執(zhí)行的順序如下:父類靜態(tài)變量、父類靜態(tài)代碼塊、子類靜態(tài)變量、子類靜態(tài)代碼塊、父類非靜態(tài)變量、父類非靜態(tài)代碼塊、父類構造函數(shù)、子類非靜態(tài)變量、子類非靜態(tài)代碼塊、子類構造函數(shù)。下面給出一個不同模塊初始化時執(zhí)行順序的一個例子。

classBase{

static{

System.out.println("Basestaticblock");

}

{

System.out.println("Baseblock");

}

publicBase(){

System.out.println("Baseconstructor");

}

}

publicclassDerivedextendsBase{

static{

System.out.println("Derivedstaticblock");

}

{

System.out.println("Derived

block");

}

publicDerived(){

System.out.println(”Derivedconstructor”);

}

publicstaticvoidmain(Stringargs[]){

newDerived();

}

}

程序運行結果為:

Basestaticblock

Derivedstaticblock

Base

block

Base

constructor

Derivedblock

Derived

constructor

常見筆試題:

下面代碼的運行結果是什么?

classBextendsObject{

static{

System.out.println("LoadB1");

}

publicB(){

System.out.println("CreateB");

}

static{

System.out.println("LoadB2");

}

}

classAextendsB{

static{

System.out.println("LoadA");

}

publicA(){

System.out.println("CreateA");

}

}

publicclassTestclass{

publicstaticvoidmain(String[]args){

newA();

}

}

A.LoadB1

LoadB2

CreateB

LoadA

CreateA

B.LoadB1

LoadB2

LoadA

CreateB

CreateA

C.LoadB2

LoadB1

CreateB

CreateA

LoadA

D.CreateB

CreateA

LoadB1

LoadB2

LoadA

答案:B。見上面講解。

6.

Java中的作用域有哪正確答案:在計算機程序中,聲明在不同地方的變量具有不同的作用域,例如局部變量、全局變量等。在Java語言中,作用域是由花括號的位置決定的,它決定了其定義的變量名的可見性與生命周期。

在Java語言中,變量的類型主要有3種:成員變量、靜態(tài)變量和局部變量。類的成員變量的作用范圍與類的實例化對象的作用范圍相同,當類被實例化時,成員變量就會在內(nèi)存中分配空間并初始化,直到這個被實例化對象的生命周期結束時,成員變量的生命周期才結束。被static修飾的成員變量被稱為靜態(tài)變量或全局變量,與成員變量不同的是,靜態(tài)變量不依賴于特定的實例,而是被所有實例所共享,也就是說,只要一個類被加載,JVM就會給類的靜態(tài)變量分配存儲空間。因此,就可以通過類名和變量名來訪問靜態(tài)變量。局部變量的作用域與可見性為它所在的花括號內(nèi)。

此外,成員變量也有4種作用域,它們的區(qū)別見下表。作用域的對比作用域與可見性當前類同一package子類其他packagepublic√√√√private√×××protected√√√×default√√××

1)public。表明該成員變量或方法對所有類或對象都是可見的,所有類或對象都可以直接訪問。

2)private。表明該成員變量或方法是私有的,只有當前類對其具有訪問權限,除此之外的其他類或者對象都沒有訪問權限。

3)protected。表明成員變量或方法對該類自身,與它在同一個包中的其它類,在其它包中的該類的子類都可見。

4)default。表明該成員變量或方法只有自己和與其位于同一包內(nèi)的類可見。若父類與子類位于同一個包內(nèi),則子類對父類的default成員變量或方法都有訪問權限;若父類與子類位于不同的package(包)內(nèi),則沒有訪問權限。

需要注意的是,這些修飾符只能修飾成員變量,不能用來修飾局部變量。private與protected不能用來修飾類(只有public、abstract或final能用來修飾類)。

常見筆試題:

下列說法中,正確的是______

A.實例方法可直接調(diào)用超類的實例方法

B.實例方法可直接調(diào)用超類的類方法

C.實例方法可直接調(diào)用其他類的實例方法

D.實例方法可直接調(diào)用本類的類方法

答案:D。當超類的實例方法或類方法為private時,是不能被子類調(diào)用的。同理,當其他類的實例方法為private時,也不能被直接調(diào)用。

7.

一個Java文件中是否可以定義多個類正確答案:一個Java文件中可以定義多個類,但是最多只能有一個類被public修飾,并且這個類的類名與文件名必須相同,若這個文件中沒有public的類,則文件名隨便是一個類的名字即可。需要注意的是,當用javac指令編譯這個.java文件時,它會給每一個類生成一個對應的.class文件,如下例定義Derived.jave為:

classBase{

publicvoidprint(){

System.out.println("Base");

}

}

publicclassDerivedextendsBase{

publicstaticvoidmain(String[]a){

Basec=newDerived();

c.print();

}

}

使用javacDerived.java指令編譯上述代碼,會生成兩個字節(jié)碼文件:Base.class與Derived.class,然后使用javaDerived指令執(zhí)行代碼,此時,控制臺的輸出結果為:Base。

8.

什么是構造函數(shù)正確答案:構造函數(shù)是一種特殊的函數(shù),用來在對象實例化時初始化對象的成員變量。在Java語言中,構造函數(shù)具有以下特點。

1)構造函數(shù)必須與類的名字相同,并且不能有返回值(返回值也不能為void)。

2)每個類可以有多個構造函數(shù)。當開發(fā)人員沒有提供構造函數(shù)時,編譯器在把源代碼編譯成字節(jié)碼的過程中會提供一個沒有參數(shù)默認的構造函數(shù),但該構造函數(shù)不會執(zhí)行任何代碼。如果開發(fā)人員提供了構造函數(shù),那么編譯器就不會再創(chuàng)建默認的構造函數(shù)了。

3)構造函數(shù)可以有0個、1個或1個以上的參數(shù)。

4)構造函數(shù)總是伴隨著new操作一起調(diào)用,且不能由程序的編寫者直接調(diào)用,必須要由系統(tǒng)調(diào)用。構造函數(shù)在對象實例化時會被自動調(diào)用,且只運行一次;而普通的方法是在程序執(zhí)行到它時被調(diào)用,且可以被該對象調(diào)用多次。

5)構造函數(shù)的主要作用是完成對象的初始化工作。

6)構造函數(shù)不能被繼承,因此,它不能被覆蓋,但是構造函數(shù)能夠被重載,可以使用不同的參數(shù)個數(shù)或參數(shù)類型來定義多個構造函數(shù)。

7)子類可以通過super關鍵字來顯式地調(diào)用父類的構造函數(shù),當父類沒有提供無參數(shù)的構造函數(shù)時,子類的構造函數(shù)中必須顯式地調(diào)用父類的構造函數(shù)。如果父類提供了無參數(shù)的構造函數(shù),此時子類的構造函數(shù)就可以不顯式地調(diào)用父類的構造函數(shù),在這種情況下編譯器會默認調(diào)用父類提供的無參數(shù)的構造函數(shù)。當有父類時,在實例化對象時會先執(zhí)行父類的構造函數(shù),然后執(zhí)行子類的構造函數(shù)。

8)當父類和子類都沒有定義構造函數(shù)時,編譯器會為父類生成一個默認的無參數(shù)的構造函數(shù),給子類也生成一個默認的無參數(shù)的構造函數(shù)。此外,默認構造器的修飾符只跟當前類的修飾符有關(例如,如果一個類被定義為public,那么它的構造函數(shù)也是public)。

引申:普通方法是否可以與構造函數(shù)有相同的方法名?

可以,示例如下。

publicclassTest{

publicTest(){

System.out.println("construct");

}

publicvoidTest(){

System.out.println("callTest");

}

publicstaticvoidmain(String[]args){

Testa=newTest();

//調(diào)用構造函數(shù)

a.Test();

//調(diào)用Test方法

}

}

程序運行結果為:

construct

callTest

常見筆試題:

1.下列關于構造方法的敘述中,錯誤的是______。

A.Java語言規(guī)定構造方法名與類名必須相同

B.Java語言規(guī)定構造方法沒有返回值,但不用void聲明

C.Java語言規(guī)定構造方法不可以重載

D.Java語言規(guī)定構造方法只能通過new自動調(diào)用

答案:C。可以定義多個構造函數(shù),只要不同的構造函數(shù)有不同的參數(shù)即可。

2.下列說法中,正確的是______。

A.class中的constructor不可省略

B.constructor必須與class同名,但方法不能與class同名

C.constructor在一個對象被new時執(zhí)行

D.一個class只能定義一個constructor

答案:C。見上面講解。

9.

為什么Java中有接口沒有任何方法正確答案:由于Java不支持多重繼承,即一個類只能有一個父類,為了克服單繼承的缺點,Java語言引入了接口這一概念。接口是抽象方法定義的集合(接口中也可以定義一些常量值),是一種特殊的抽象類。接口中只包含方法的定義,沒有方法的實現(xiàn)。接口中的所有方法都是抽象的。接口中成員的作用域修飾符都是public,接口中的常量值默認使用publicstaticfinal修飾。由于一個類可以實現(xiàn)多個接口,因此通??梢圆捎脤崿F(xiàn)多個接口的方式來間接達到多重繼承的目的。

在Java語言中,有些接口內(nèi)部沒有聲明任何方法,也就是說,實現(xiàn)這些接口的類不需要重寫任何方法,這些沒有任何方法聲明的接口又被叫做標識接口,標識接口對實現(xiàn)它的類沒有任何語義上的要求,它僅僅充當一個標識的作用,用來表明實現(xiàn)它的類屬于一個特定的類型。這個標簽類似于汽車的標志圖標,每當人們看到一個汽車的標志圖標時,就能知道這款汽車的品牌。Java類庫中已存在的標識接口有Cloneable和Serializable等。在使用時會經(jīng)常用instanceof來判斷實例對象的類型是否實現(xiàn)了一個給定的標識接口。

下面通過一個例子來詳細說明標識接口的作用。例如要開發(fā)一款游戲,游戲里面有一個人物專門負責出去尋找有用的材料,假設這個人物只收集礦石和武器,而不會收集垃圾。下面通過標識接口來實現(xiàn)這個功能。

importJava.util.ArrayList;

interfaceStuff{}

//礦石

interfaceOreextendsStuff{}

//武器

interfaceWeaponextendsStuff{}

//垃圾

interfaceRubbishextendsStuff{}

//金礦

classGoldimplementsOre{

publicStringtoString(){

return"Gold";

}

}

//銅礦

classCopperimplementsOre{

publicStringtoString(){

return"Copper";

}

}

//槍

classGunimplementsWeapon{

publicStringtoString(){

return"Gun";

}

}

//榴彈

classGrenadeimplementsWeapon{

publicStringtoString(){

return"Grenade";

}

}

classStoneimplementsRubbish{

publicStringtoString(){

return"Stone";

}

}

publicclassTest{

publicstaticArrayList<Stuff>collectStuff(Stuff[]s){

ArrayList<Stuff>al=newArrayList<Stuff>();

for(inti=0;i<s.length;i++){

if(!(s[i]instanceofRubbish))

al.add(s[i]);

}

returnal;

}

publicstaticvoidmain(String[]args){

Stuff[]s={newGold(),newCopper(),newGun(),newGrenade(),newStone()};

ArrayList<Stuff>al=collectStuff(s);

System.out.println("TheusefullStuffcollectedis:");

for(inti=0;i<al.size();i++)

System.out.println(al.get(i));

}

}

程序運行結果為:

TheusefullStuffcollectedis:

Gold

Copper

Gun

Grenade

在上例中,設計了3個接口:Ore、Weapon和Rubbish分別代表礦石、武器和垃圾,只要是實現(xiàn)Ore或Weapon的類,游戲中的角色都會認為這是有用的材料,例如Gold、Copper、Gun、Grenade,因此會收集;只要是實現(xiàn)Rubbish的類,都會被認為是無用的東西,例如Stone,因此不會被收集。

常見筆試題:

不能用來修飾interface的有______

A.private

B.public

C.protected

D.static

答案:A、C、D。見上面講解。

10.

Java中的clone方法有什么作用正確答案:由于指針不僅會給開發(fā)人員帶來使用上的不便,而且也是造成程序不穩(wěn)定的根源,為了消除C/C++語言的這些缺點,Java語言取消了指針的概念,但這只是在Java語言中沒有明確提供指針的概念與用法,而實質上每個new語句返回的都是一個指針的引用,只不過在大部分情況下開發(fā)人員不需要關心如何去操作這個指針而已。

由于Java取消了指針的概念,因此開發(fā)人員在編程中往往忽略了對象和引用的區(qū)別,示例如下。

classObj{

publicvoidsetStr(Stringstr){

this.str=str;

}

privateStringstr="defaultvalue";

publicStringtoString(){

returnstr;

}

}

publicclassTestRef{

privateObjaObj=newObj();

privateintaInt=0;

publicObjgetAObj(){

returnaObj;

}

publicintgerAInt(){

returnaInt;

}

publicvoidchangeObj(ObjinObj){

inObj.setStr("changedvalue");

}

publicvoidchangeInt(intinInt){

inInt=1;

}

publicstaticvoidmain(String[]args){

TestRefoRef=newTestRef();

System.out.println("*******************引用類型*******************");

System.out.println("調(diào)用changeObj()前:"+oRef.getAObj());

oRef.changeObj(oRef.getAObj());

System.out.println("調(diào)用changeObj()后:"+oRer.getAObj());

System.out.println("*******************基本數(shù)據(jù)類型*******************");

System.out.println("調(diào)用changeInt()前:"+oRef.getAInt());

oRef.changeInt(oRef.getAInt()).

System.out.println("調(diào)用changeInt()后:"+oRef.getAInt());

}

}

程序運行結果為:

*******************引用類型*******************

調(diào)用changeObj()前:defaultvalue

調(diào)用changeObj()后:changedvalue

*******************基本數(shù)據(jù)類型*******************

調(diào)用changeInt()前:0

調(diào)用changeInt()后:0

上面兩個看似類似的方法卻有著不同的運行結果,主要原因是Java在處理基本數(shù)據(jù)類型(例如int、char、double等)時,都是采用按值傳遞(傳遞的是輸入?yún)?shù)的復制)的方式執(zhí)行,除此之外的其他類型都是按引用傳遞(傳遞的是對象的一個引用)的方式執(zhí)行。對象除了在函數(shù)調(diào)用時是引用傳遞,在使用“=”賦值時也采用引用傳遞,示例代碼如下。

ClassObj{

privateintaInt=0;

publicintgetAInt(){

returnaInt;

}

publicvoidsetAInt(intint1){

aInt=int1;

}

publicvoidchangeInt(){

this.aInt=1;

}

}

publicclassTestRef{

publicstaticvoidmain(String[]args){

Obja=newObj();

Objb=a;

b.changeInt();

System.out.println("a:"+a.getAInt());

System.out.println("b:"+b.getAInt());

}

}

程序運行結果為:

a:1

b:1

在實際編程中,經(jīng)常會遇到從某個已有的對象A創(chuàng)建出另外一個與A具有相同狀態(tài)的對象B,并且對B的修改不會影響到A的狀態(tài),例如,Prototype(原型)模式中,就需要clone一個對象實例。在Java語言中,僅僅通過簡單的賦值操作顯然無法達到這個目的,而Java提供了一個簡單有效的clone()方法來滿足這個需求。

Java中的所有類默認都繼承自Object類,而Object類中提供了一個clone()方法。這個方法的作用是返回一個Object對象的復制。這個復制函數(shù)返回的是一個新的對象而不是一個引用。那么怎樣使用這個方法呢?以下是使用clone()方法的步驟。

1)實現(xiàn)clone的類首先需要繼承Cloneable接口。Cloneable接口實質上是一個標識接口,沒有任何接口方法。

2)在類中重寫Object類中的clone()方法。

3)在clone方法中調(diào)用super.clone()。無論clone類的繼承結構是什么,super.clone()都會直接或間接調(diào)用java.lang.Object類的clone()方法。

4)把淺復制的引用指向原型對象新的克隆體。

對上面的例子引入clone方法如下:

classObjimplementsCloneable{

privateintaInt=0;

publicintgetAInt(){

returnaInt;

}

publicvoidsetAInt(intint1){

aInt=int1;

}

publicvoidchangeInt(){

this.aInt=1;

}

publicObjectclone(){

Objecto=null;

try{

o=(Obj)super.clone();

}catch(CloneNotsupportedExceptione){

e.printStackTrace();

}

returno;

}

}

publicclassTestRef{

publicstaticvoidmain(String[]args){

Obja=newObj();

Objb=(Obj)a.clone();

b.changeInt();

System.out.println("a:"+a.getAInt());

System.out.println("b:"+b.getAInt());

}

}

程序運行結果為:

a:0

b:1

在C++語言中,當開發(fā)人員自定義復制構造函數(shù)時,會存在淺復制與深復制之分。Java語言在重載clone()方法時也存在同樣的問題,當類中只有一些基本的數(shù)據(jù)類型時,采用上述方法就可以了,但是當類中包含了一些對象時,就需要用到深復制了,實現(xiàn)方法是在對對象調(diào)用clone()方法完成復制后,接著對對象中的非基本類型的屬性也調(diào)用clone()方法完成深復制,示例如下。

importjava.util.Date;

classObjimplementsCloneable{

privateDatebirth=newDate();

publicDategetBirth(){

returnbirth;

}

publicvoidsetBirth(Datebirth){

this.birth=birth;

}

publicvoidchangeDate(){

this.birth.setMonth(4);

}

publicObjectclone(){

Objo=null;

try{

o=(Obj)super.clone();

}catch(CloneNotSupportedExceptione){

e.printStackTrace();

//實現(xiàn)深復制

o.birth=(Date)this.getBirth().clone();

returno;

}

}

publicclassTestRef{

publicstaticvoidmain(String[]args){

Obja=newObj();

Objb=(Obj)a.clone();

b.changeDate();

System.out.println("a="+a.getBirth());

System.out.println("b="+b.getBirth());

}

}

程序運行結果為:

a=SatJul1323:58:56CST2013

b=MonMay1323:58:56CST2013

那么在編程時,如何選擇使用哪種復制方式呢?首先,檢查類有無非基本類型(即對象)的數(shù)據(jù)成員。若沒有,則返回super.clone()即可;若有,確保類中包含的所有非基本類型的成員變量都實現(xiàn)了深復制。

Objecto=super.clone();//先執(zhí)行淺復制

對每一個對象attr執(zhí)行以下語句:

o.attr=this.getAttr().clone();

最后返回o。

需要注意的是,clone()方法的保護機制在Object中clone()是被聲明為protected的。以User類為例,通過聲明為protected,就可以保證只有User類里面才能“克隆”User對象,原理可以參考前面關于public、protected、private的講解。

引申:淺復制和深復制有什么區(qū)別?

淺復制(ShallowClone):被復制對象的所有變量都含有與原來對象相同的值,而所有對其他對象的引用仍然指向原來的對象。換言之,淺復制僅僅復制所考慮的對象,而不復制它所引用的對象。

深復制(DeepClone):被復制對象的所有變量都含有與原來對象相同的值,除去那些引用其他對象的變量。那些引用其他對象的變量將指向被復制的新對象,而不再是原有的那些被引用的對象。換言之,深復制把復制的對象所引用的對象都復制了一遍。

假如定義如下一個類。

classTest{

publicinti;

publicStringBuffers;

}

下圖給出了對這個類的對象進行復制時,淺復制與深復制的區(qū)別。

11.

什么事是反射機制正確答案:反射機制是Java語言中一個非常重要的特性,它允許程序在運行時進行自我檢查,同時也允許對其內(nèi)部的成員進行操作。雖然這個特性在實際開發(fā)時使用得不多,但是像Pascal、C和C++等語言根本就沒有提供這樣的特性。由于反射機制能夠實現(xiàn)在運行時對類進行裝載,因此能夠增加程序的靈活性,但是不恰當?shù)厥褂梅瓷錂C制,也會嚴重影響系統(tǒng)的性能。

具體而言,反射機制提供的功能主要有:得到一個對象所屬的類;獲取一個類的所有成員變量和方法;在運行時創(chuàng)建對象;在運行時調(diào)用對象的方法。

其實,反射機制非常重要的一個作用就是可以在運行時動態(tài)地創(chuàng)建類的對象,示例如下。

classBase{

publicvoidf(){

System.out.println("Base");

}

}

classSubextendsBase{

publicvoidf(){

System.out.println("Sub");

}

}

publicclassTest{

publicstaticvoidmain(String[]args){

try{//使用反射機制加載類

Classc=Class.forName("Sub");

Baseb=(Base)c.newInstance();

b.f();

}catch(Exceptione){

e.printStackTrace();

}

}

}

程序運行結果為:

Sub

在反射機制中,class是一個非常重要的類,那么如何才能獲取class類呢?總共有如下3種方法可以獲取到class類:

1)class.forName(“類的路徑”),如上例所示。

2)類名.class。

3)實例.getClass()。

常見筆試題:

Java創(chuàng)建對象的方式有幾種?

答案:共有4種創(chuàng)建對象的方法。

1)通過:new語句實例化一個對象。

2)通過反射機制創(chuàng)建對象,見上述講解。

3)通過clone()方法創(chuàng)建一個對象。

4)通過反序列化的方式創(chuàng)建對象。

12.

package有什么作用正確答案:package的中文意思是“包”,它是一個比較抽象的邏輯概念,其宗旨是把.java文件(Java源文件)、.class文件(編譯后的文件)以及其他resource文件(例如.xml文件、avi文件、.mp3文件、.txt文件等)有條理地進行一個組織,以供使用。它類似于Linux文件系統(tǒng),有一個根,從根開始有目錄和文件,然后目錄中嵌套目錄。具體而言,package主要有以下兩個作用:第一,提供多層命名空間,解決命名沖突,通過使用package,使得處于不同package中的類可以存在相同的名字。第二,對類按功能進行分類,使項目的組織更加清晰。當開發(fā)一個有非常多的類的項目時,如果不使用package對類進行分類,而是把所有類都放在一個package下,這樣的代碼不僅可讀性差,而且可維護性也不好,會嚴重影響開發(fā)效率。

package的用法一般如下(源文件所在目錄為當前目錄):

1)在每個源文件的開頭加上"packagepackagename;",然后源文件所在目錄下創(chuàng)建一個新目錄,名稱為packagename。

2)用javac指令編譯每個sourcename.java源文件,將生成的sourcename.classname文件復制到packagename目錄。

3)用java指令運行程序:javapackagename.sourcename。

以下是一個簡單的程序示例。

packagecom.pkg;

publicclassTestPackage{

publicstaticvoidmain(String[]args){

system.out.println("Helloworld");

}

}

通過運行指令javac-d.TestPackage.java編譯代碼,會在當前目錄下自動生成目錄com/pkg,然后通過運行指令javacom.pkg.TestPackage執(zhí)行程序,程序運行結果為:

Helloworld

常見筆試題:

下列說法中,正確的是______。

A.Java中包的主要作用是實現(xiàn)跨平臺功能

B.package語句只能放在import語句后面

C.包(package)由一組類(class)和接口(interface)組成

D.可以用#include關鍵字來表明來自其他包中的類

答案:C。見上面講解。

13.

如何實現(xiàn)類似于C語言中函數(shù)指針的功能正確答案:在C語言中,有一個非常重要的概念——函數(shù)指針,其最重要的功能是實現(xiàn)回調(diào)函數(shù)。什么是回調(diào)函數(shù)呢?所謂回調(diào)函數(shù),就是指函數(shù)先在某處注冊,而它將在稍后某個需要的時候被調(diào)用。在Windows系統(tǒng)中,開發(fā)人員想讓系統(tǒng)動態(tài)鏈接庫(DynamicLinkLibrary,DLL)調(diào)用自己編寫的一個方法,于是利用DLL當中回調(diào)函數(shù)的接口來編寫程序,通過傳遞一個函數(shù)的指針來被調(diào)用,這個過程就稱為回調(diào)?;卣{(diào)函數(shù)一般用于截獲消息、獲取系統(tǒng)信息或處理異步事件。舉個簡單例子,程序員何昊編寫了一段程序a,其中預留有回調(diào)函數(shù)接口,并封裝好了該程序。程序員薛鵬要讓a調(diào)用自己的程序b中的一個方法,于是,他通過a中的接口回調(diào)屬于自己的程序b中的那個方法。

函數(shù)指針一般作為函數(shù)的參數(shù)來使用,開發(fā)人員在使用時可以根據(jù)自己的需求傳遞自定義的函數(shù)來實現(xiàn)指定的功能,例如,在實現(xiàn)排序算法時,可以通過傳遞一個函數(shù)指針來決定兩個數(shù)的先后順序,從而最終決定該算法是按升序還是降序排列。

在Java語言中沒有指針的概念,那么如何才能在Java語言中實現(xiàn)類似于函數(shù)指針的功能呢?可以利用接口與類來實現(xiàn)同樣的效果。具體而言,應先定義一個接口,然后在接口中聲明要調(diào)用的方法,接著實現(xiàn)這個接口,最后把這個實現(xiàn)類的一個對象作為參數(shù)傳遞給調(diào)用程序,調(diào)用程序通過這個參數(shù)來調(diào)用指定的函數(shù),從而實現(xiàn)回調(diào)函數(shù)的功能,示例如下。

//接口中定義了一個用來比較大小的方法

interfaceIntCompare{

publicintcmp(inta,intb);

classCmp1implementsIntCompare{

publicintcmp(inta,intb){

if(a>b)

return1;

elseif(a<b)

return-1;

else

return0;

}

}

classCmp2implementsIntCompare{

publicintcmp(inta,intb){

if(a>b)

return-1;

elseif(a<b)

return1;

else

return0;

}

}

publicclassTest{

publicstaticvoidinsertSort(int[]a,IntComparecmp){

if(a!=null){

for(inti=1;i<a.length;i++){

inttemp=a[i],j=i;

if(cmp.cmp(a[j-1],temp)==1){

while(j>=1&&cmp.cmp(a[j-1],temp)=1){

a[j]=a[j-1];

j--;

}

}

a[j]=temp;

}

}

}

publicstaticvoidmain(String[]args){

int[]array1={7,3,19,40,4,7,1};

insertSort(array1,newCmp1());

System.out.print("升序排列:");

for(inti=0;i<array1.length;i++)

system.out.print(array1[i]+"");

system.out.println();

int[]array2={7,3,19,40,4,7,1};

insertSort(array2,newCmp2());

System.out.print("降序排列:");

for(inti=0;i<array2.length;i++)

system.out.print(array2[i]+"");

}

}

程序運行結果為:

升序排列:134771940

降序排列:401977431

上例定義了一個用來比較大小的接口IntCompare,這個接口實際上充當了C語言中函數(shù)指針的功能,在使用時,開發(fā)人員可以根據(jù)實際需求傳入自定義的類。在上例中分別有兩個類cmp1和Cmp2都實現(xiàn)了這個接口,分別用來在實現(xiàn)升序排序和降序排序時使用。其實這也是策略設計模式所用到的思想。

4.2面向對象技術

14.

面向對象與面向過程有什么區(qū)別正確答案:面向對象中的對象不是指女朋友,它是一種編程術語。面向對象是當今軟件開發(fā)方法的主流方法之一,它是把數(shù)據(jù)及對數(shù)據(jù)的操作方法放在一起,作為一個相互依存的整體,即對象。對同類對象抽象出其共性,即類,類中的大多數(shù)數(shù)據(jù),只能被本類的方法進行處理。類通過一個簡單的外部接口與外界發(fā)生關系,對象與對象之間通過消息進行通信。程序流程由用戶在使用中決定,例如,站在抽象的角度,人具有身高、體重、年齡、血型等一些特征,人會勞動、人都會直立行走、人都會吃飯、人都會用自己的頭腦去創(chuàng)造工具等這些方法,人僅僅只是一個抽象的概念,它是不存在的實體,但是所有具備人這個群體的屬性與方法的對象都叫人,這個對象人是實際存在的實體,每個人都是人這個群體的一個對象。

而面向過程是一種以事件為中心的開發(fā)方法,就是自頂向下順序執(zhí)行,逐步求精,其程序結構是按功能劃分為若干個基本模塊,這些模塊形成一個樹狀結構,各模塊之間的關系也比較簡單,在功能上相對獨立,每一模塊內(nèi)部一般都是由順序、選擇和循環(huán)3種基本結構組成,其模塊化實現(xiàn)的具體方法是使用子程序,而程序流程在寫程序時就已經(jīng)決定。以五子棋為例,面向過程的設計思路就是首先分析問題的步驟:第一步,開始游戲;第二步,黑子先走;第三步,繪制畫面;第四步,判斷輸贏;第五步,輪到白子;第六步,繪制畫面;第七步,判斷輸贏;第八步,返回第二步;第九步,輸出最后結果。把上面每個步驟用分別的函數(shù)來實現(xiàn),就是一個面向過程的開發(fā)方法。

具體而言,面向對象與面向過程主要有以下幾個方面的不同之處。

1)出發(fā)點不同。面向對象方法是用符合常規(guī)思維的方式來處理客觀世界的問題,強調(diào)把問題域的要領直接映射到對象及對象之間的接口上。而面向過程方法強調(diào)的則是過程的抽象化與模塊化,它是以過程為中心構造或處理客觀世界問題的。

2)層次邏輯關系不同。面向對象方法則是用計算機邏輯來模擬客觀世界中的物理存在,以對象的集合類作為處理問題的基本單位,盡可能地使計算機世界向客觀世界靠攏,以使問題的處理更清晰直接,面向對象方法是用類的層次結構來體現(xiàn)類之間的繼承和發(fā)展。而面向過程方法處理問題的基本單位是能清晰準確地表達過程的模塊,用模塊的層次結構概括模塊或模塊間的關系與功能,把客觀世界的問題抽象成計算機可以處理的過程。

3)數(shù)據(jù)處理方式與控制程序方式不同。面向對象方法將數(shù)據(jù)與對應的代碼封裝成一個整體,原則上其他對象不能直接修改其數(shù)據(jù),即對象的修改只能由自身的成員函數(shù)完成,控制程序方式上是通過“事件驅動”來激活和運行程序。而面向過程方法是直接通過程序來處理數(shù)據(jù),處理完畢后即可顯示處理結果,在控制程序方式上是按照設計調(diào)用或返回程序,不能自由導航,各模塊之間存在著控制與被控制、調(diào)用與被調(diào)用的關系。

4)分析設計與編碼轉換方式不同。面向對象方法貫穿于軟件生命周期的分析、設計及編碼中,是一種平滑過程,從分析到設計再到編碼是采用一致性的模型表示,即實現(xiàn)的是一種無縫連接。而面向過程方法強調(diào)分析、設計及編碼之間按規(guī)則進行轉換,貫穿于軟件生命周期的分析、設計及編碼中,實現(xiàn)的是一種有縫的連接。

15.

面向對象有哪特征正確答案:面向對象的主要特征包括抽象、繼承、封裝和多態(tài)。

1)抽象。抽象就是忽略一個主題中與當前目標無關的那些方面,以便更充分地注意與當前目標有關的方面。抽象并不打算了解全部問題,而只是選擇其中的一部分,暫時不用部分細節(jié)。抽象包括兩個方面:一是過程抽象;二是數(shù)據(jù)抽象。

2)繼承。繼承是一種聯(lián)結類的層次模型,并且允許和鼓勵類的重用,它提供了一種明確表述共性的方法。對象的一個新類可以從現(xiàn)有的類中派生,這個過程稱為類繼承。新類繼承了原始類的特性,新類稱為原始類的派生類(子類),而原始類稱為新類的基類(父類)。派生類可以從它的基類那里繼承方法和實例變量,并且派生類可以修改或增加新的方法使之更適合特殊的需要。

3)封裝。封裝是指將客觀事物抽象成類,每個類對自身的數(shù)據(jù)和方法實行保護。類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。

4)多態(tài)。多態(tài)是指允許不同類的對象對同一消息作出響應。多態(tài)包括參數(shù)化多態(tài)和包含多態(tài)。多態(tài)性語言具有靈活、抽象、行為共享、代碼共享等優(yōu)勢,很好地解決了應用程序函數(shù)同名問題。

16.

面向對象的開發(fā)方式有什么優(yōu)點正確答案:采用面向對象的開發(fā)方式有諸多的優(yōu)點,下面主要介紹其中3個優(yōu)點。

1)較高的開發(fā)效率。采用面向對象的開發(fā)方式,可以對現(xiàn)實的事物進行抽象,可以把現(xiàn)實的事物直接映射為開發(fā)的對象,與人類的思維過程相似,例如可以設計一個Car類來表示現(xiàn)實中的汽車,這種方式非常直觀明了,也非常接近人們的正常思維。同時,由于面向對象的開發(fā)方式可以通過繼承或者組合的方式來實現(xiàn)代碼的重用,因此可以大大地提高軟件的開發(fā)效率。

2)保證軟件的魯棒性。正是由于面向對象的開發(fā)方法有很高的重用性,在開發(fā)的過程中可以重用已有的而且在相關領域經(jīng)過長期測試的代碼,因此,自然而然地對軟件的魯棒性起到了良好的促進作用。

3)保證軟件的高可維護性。由于采用面向對象的開發(fā)方式,使得代碼的可讀性非常好,同時面向對象的設計模式也使得代碼結構更加清晰明了。同時針對面向對象的開發(fā)方式,已有許多非常成熟的設計模式,這些設計模式可以使程序在面對需求的變更時,只需要修改部分的模塊就可以滿足需求,因此維護起來非常方便。

17.

什么是繼承正確答案:繼承是面向對象中的一個非常重要的特性。通過繼承,子類可以使用父類中的一些成員變量與方法,從而能夠提高代碼的復用性,提高開發(fā)效率。在Java語言中,被繼承的類叫基類(superclass)或父類,繼承基類或父類的類叫派生類或子類(subclass)。繼承是通過extends關鍵字來實現(xiàn)的,使用格式為:class子類名extends父類名。

繼承主要有如下幾個特性:

1).Java語言不支持多重繼承,也就是說,子類至多只能有一個父類,但是可以通過實現(xiàn)多個接口來達到多重繼承的目的。

2)子類只能繼承父類的非私有(public與protected)成員變量與方法。

3)當子類中定義的成員變量和父類中定義的成員變量同名時,子類中的成員變量會覆蓋父類的成員變量,而不會繼承。

4)當子類中的方法與父類中的方法有相同的函數(shù)簽名(相同的方法名,相同的參數(shù)個數(shù)與類型)時,子類將會覆蓋父類的方法,而不會繼承。

常見筆試題:

下列有關繼承的說法中,正確的是______。

A.子類能繼承父類的所有方法和狀態(tài)

B.子類能繼承父類的非私有方法和狀態(tài)

C.子類只能繼承父類public方法和狀態(tài)

D.子類能繼承父類的方法,而不是狀態(tài)

答案:B。見上面講解。

18.

組合和繼承有什么區(qū)別正確答案:組合和繼承是面向對象中兩種代碼復用的方式。組合是指在新類里面創(chuàng)建原有類的對象,重復利用已有類的功能。繼承是面向對象的主要特性之一,它允許設計人員根據(jù)其他類的實現(xiàn)來定義一個類的實現(xiàn)。組合和繼承都允許在新的類中設置子對象(subobject),只是組合是顯式的,而繼承則是隱式的。組合和繼承存在著對應關系:組合中的整體類和繼承中的子類對應,組合中的局部類和繼承中的父類對應。

二者的區(qū)別在哪里呢?首先分析一個實例。Car表示汽車對象,Vehicle表示交通工具對象,Tire表示輪胎對象。三者的類關系如下圖所示。

從圖中可以看出,Car是Vehicle的一種,因此是一種繼承關系(又被稱為“is-a”關系);而car包含了多個Tire,因此是一種組合關系(又被稱為“has-a”關系)。其實現(xiàn)方式如下:繼承組合classVerhicle{}classCarextendsVerhicle{}classTire{}classCarextendsVerhicle{privateTiret=newTire();}

既然繼承和組合都可以實現(xiàn)代碼的重用,那么在實際使用時又該如何選擇呢?一般情況下,遵循以下兩點原則。

1)除非兩個類之間是“is-a”的關系,否則不要輕易地使用繼承,不要單純地為了實現(xiàn)代碼的重用而使用繼承,因為過多地使用繼承會破壞代碼的可維護性,當父類被修改時,會影響到所有繼承自它的子類,從而增加程序的維護難度與成本。

2)不要僅僅為了實現(xiàn)多態(tài)而使用繼承,如果類之間沒有“is-a”的關系,可以通過實現(xiàn)接口與組合的方式來達到相同的目的。設計模式中的策略模式可以很好地說明這一點,采用接口與組合的方式比采用繼承的方式具有更好的可擴展性。

由于Java語言只支持單繼承,如果想同時繼承兩個類或多個類,在Java中是無法直接實現(xiàn)的。同時,在Java語言中,如果繼承使用太多,也會讓一個class里面的內(nèi)容變得臃腫不堪。所以,在Java語言中,能使用組合就盡量不要使用繼承。

19.

多態(tài)的實現(xiàn)機制是什么正確答案:多態(tài)是面向對象程序設計中代碼重用的一個重要機制,它表示當同一個操作作用在不同對象時,會有不同的語義,從而會產(chǎn)生不同的結果,例如,同樣是執(zhí)行“+”操作,“3+4”用來實現(xiàn)整數(shù)相加,而“3”+“4”卻實現(xiàn)了字符串的連接。在Java語言中,多態(tài)主要有以下兩種表現(xiàn)方式:

1)方法的重載(overload)。重載是指同一個類中有多個同名的方法,但這些方法有著不同的參數(shù),因此在編譯時就可以確定到底調(diào)用哪個方法,它是一種編譯時多態(tài)。重載可以被看作一個類中的方法多態(tài)性。

2)方法的覆蓋(override)。子類可以覆蓋父類的方法,因此同樣的方法會在父類與子類中有著不同的表現(xiàn)形式。在Java語言中,基類的引用變量不僅可以指向基類的實例對象,也可以指向其子類的實例對象。同樣,接口的引用變量也可以指向其實現(xiàn)類的實例對象。而程序調(diào)用的方法在運行期才動態(tài)綁定(綁定指的是將一個方法調(diào)用和一個方法主體連接到一起),就是引用變量所指向的具體實例對象的方法,也就是內(nèi)存里正在運行的那個對象的方法,而不是引用變量的類型中定義的方法。通過這種動態(tài)綁定的方法實現(xiàn)了多態(tài)。由于只有在運行時才能確定調(diào)用哪個方法,因此通過方法覆蓋實現(xiàn)的多態(tài)也可以被稱為運行時多態(tài),示例如下。

classBase{

publicBase(){

g();

}

publicvoidf(){

System.out.println("Basef()");

}

publicvoidg(){

System.out.println("Baseg()");

}

}

classDerivedextendsBase{

publicvoidf(){

System.out.println("Derivedf()");

}

publicvoidg(){

System.out.println("Derivedg()");

}

}

publicclassTest{

publicstaticvoidmain(String[]args){

Baseb=newDerived();

b.f();

b.g();

}

}

程序運行結果為:

Derivedg()

Derivedf()

Derivedg()

上例中,由于子類Derived的f()方法和g()方法與父類Base的方法同名,因此Derived的方法會覆蓋Base的方法。在執(zhí)行Baseb=newDerived()語句時,會調(diào)用Base類的構造函數(shù),而在Base的構造函數(shù)中,執(zhí)行了g()方法,由于Java語言的多態(tài)特性,此時會調(diào)用子類Derived的g()方法,而非父類Base的g()方法,因此會輸出Derivedg()。由于實際創(chuàng)建的是Derived類的對象,后面的方法調(diào)用都會調(diào)用子類Derived的方法。

此外,只有類中的方法才有多態(tài)的概念,類中成員變量沒有多態(tài)的概念,示例如下。

classBase{

publicinti=1;

}

classDerivedextendsBase{

publicinti=2;

}

publicclassTest{

publicstaticvoidmain(String[]args){

Baseb=newDerived();

System.out.println(b.i);

}

}

程序運行結果為:

1

由此可見,成員變量是無法實現(xiàn)多態(tài)的,成員變量的值取父類還是子類并不取決于創(chuàng)建對象的類型,而是取決于所定義變量的類型,這是在編譯期間確定的。在上例中,由于b所屬的類型為Base,b.i指的是Base類中定義的i,因此程序輸出結果為1。

常見筆試題:

Java中提供了哪兩種用于多態(tài)的機制?

答案:編譯時多態(tài)和運行時多態(tài)。編譯時多態(tài)是通過方法的重載實現(xiàn)的,運行時多態(tài)是通過方法的覆蓋(子類覆蓋父類方法)實現(xiàn)的。

20.

重載和覆蓋有什么區(qū)別正確答案:重載(overload)和覆蓋(override)是Java多態(tài)性的不同表現(xiàn)方式。其中,重載是在一個類中多態(tài)性的一種表現(xiàn),是指在一個類中定義了多個同名的方法,它們或有不同的參數(shù)個數(shù)或有不同的參數(shù)類型。在使用重載時,需要注意以下幾點:

1)重載是通過不同的方法參數(shù)來區(qū)分的,例如不同的參數(shù)個數(shù)、不同的參數(shù)類型或不同的參數(shù)順序。

2)不能通過方法的訪問權限、返回值類型和拋出的異常類型來進行重載。

3)對于繼承來說,如果基類方法的訪問權限為private,那么就不能在派生類對其重載;如果派生類也定義了一個同名的函數(shù),這只是一個新的方法,不會達到重載的效果。

覆蓋是指派生類函數(shù)覆蓋基類函數(shù)。覆蓋一個方法并對其重寫,以達到不同的作用。在使用覆蓋時需要注意以下幾點:

1)派生類中的覆蓋方法必須要和基類中被覆蓋的方法有相同的函數(shù)名和參數(shù)。

2)派生類中的覆蓋方法的返回值必須和基類中被覆蓋白方法的返回值相同。

3)派生類中的覆蓋方法所拋出的異常必須和基類(或是其子類)中被覆蓋的方法所拋出的異常一致。

4)基類中被覆蓋的方法不能為private,否則其子類只是定義了一個方法,并沒有對其覆蓋。

重載與覆蓋的區(qū)別主要有以下幾個方面:

1)覆蓋是子類和父類之間的關系,是垂直關系;重載是同一個類中方法之間的關系,是水平關系。

2)覆蓋只能由一個方法或只能由一對方法產(chǎn)生關系;重載是多個方法之間的關系。

3)覆蓋要求參數(shù)列表相同;重載要求參數(shù)列表不同。

4)覆蓋關系中,調(diào)用方法體是根據(jù)對象的類型(對象對應存儲空間類型)來決定;而重載關系是根據(jù)調(diào)用時的實參表與形參表來選擇方法體的。

常見筆試題:

如下代碼的運行結果是什么?

classSuper{

publicintf(){

return1;

}

}

publicclassSubClas

溫馨提示

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

評論

0/150

提交評論