#分享 【程式學習成果分享】Java工程師面試觀念考題整理(part 3)

2022年3月31日 00:25
part 1在這👇👇
part 2在這👇👇
關於物件導向的詮釋,可參考這篇文章👇👇,第31題與這方面的內容有關
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (文長,請耐心服用) 21. 說明>>和>>>的差別。 解答: >>和>>>都是用來進行右移運算,不過兩者的差別在於右移運算後,>>會將左邊空出來的所有位元都補上原來最左邊的位元值(sign bit),而>>>則是都補0,如下圖所示。
imgur
22. 下圖中的程式會輸出什麼內容?
imgur
解答: (1)main方法內只有一行註解,照理說程式不會印出任何東西,不過仔細觀察註解中的文字,可以發現\u000d是一個Unicode值(以\uXXXX的形式表示的跳脫序列)。如果一個Java程式當中有出現Unicode值,不管Unicode值出現在哪裡,Java編譯器都會在編譯程式之前「預先」將Unicode值轉義為對應的字元。 (2)編譯器在編譯程式之前會先將\u000d轉義,而\u000d代表的是CR(回車),所以編譯器會把程式解讀成下圖中的樣子,再進行編譯。
imgur
(3)由上圖可知,程式會印出test。下面再舉幾個Unicode值預先被轉義的例子。
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
23. 下圖中的程式會輸出什麼內容?
imgur
解答: 假設T是資料型態,(T)、正號和負號的結合性都是由右到左,所以如果把本題的程式改成下圖中的樣子,不必要的空格全部去掉,就會比較好理解。首先,「(long) -1」會得到-1L,接著「(int) +(long) -1」會得到-1,因為它相當於「(int) +-1L」,+-1L(即-1L)被強制轉型為int。依此類推,最後等號右邊的運算式會得到byte型態的1,故本題的程式會印出1。
imgur
24. 下圖中的程式會不會發生編譯錯誤?如果不會的話,會輸出什麼內容?
imgur
解答: (1)Java並不像C語言、C++和C#一樣有支援goto,不過Java允許我們建立label,它可以跟break並用,達到類似goto的效果,如圖36和圖37所示。同樣的,label也可以跟continue並用,如圖38所示。 (圖36)
imgur
(圖37)
imgur
(圖38)
imgur
(2)在本題的程式當中,http是label的名稱,而"www.google.com"則是註解的內容。雖然http沒有被用到,但程式依然可以正確執行,印出「我常用的搜尋引擎:」。(註:如果label的名稱和冒號之後沒有其它敘述,程式就會發生編譯錯誤,所以在本題的程式當中,如果那個return敘述沒有寫,程式會發生編譯錯誤。) (3)相關的內容可參考part 2的第13題。 25. 說明break敘述和continue敘述的差別。 解答: (1)break敘述可以用於switch敘述和迴圈,而continue敘述只能用在迴圈。 (2)break敘述是用來跳出switch敘述或「整個」迴圈,而continue敘述則是用來跳出「當下的那一輪」迴圈,繼續下一輪迴圈。 (3)break和continue都可以與label並用,相關的內容可參考上一題。 26. 什麼是無窮迴圈? 解答: 無窮迴圈指的是永遠不會終止的迴圈,也就是說,無窮迴圈的continuation condition永遠都是true。舉例來說,圖39、圖40、圖41和圖42當中的迴圈都是無窮迴圈。 (圖39)
imgur
(圖40)
imgur
(圖41)
imgur
(圖42)
imgur
27. 下圖中的程式會輸出什麼內容?
imgur
解答: (1)本題考的是Dangling else的問題,從縮排來看,else子句是跟第一個if子句配對,但其實else子句是跟第二個if子句配對,如下圖所示,所以本題的程式不會印出任何東西。
imgur
(2)如果要讓else子句跟第一個if子句配對,應該用大括號將第二個if敘述包住,如下圖所示。
imgur
28. byte、long或String可不可以適用於switch敘述? 解答: (1)只有byte、Byte、short、Short、int、Integer、char、Character、String和enum可適用於switch敘述,如下方的兩張圖所示。
imgur
imgur
(2)要注意的是,null不可用於switch敘述,如下方的兩張圖所示。
imgur
imgur
29. 沒有主檔名的Java程式可不可以被執行? 解答: 每個Java檔案只能有一個public type(public class、public interface、public enum和public abstract class都算public type),而且public type的名稱必須跟主檔名相同,但是public type不可能沒有名稱,所以".java"當中必須沒有public type,才可以執行。 30. 說明類別和物件。 解答: (1)物件模擬真實世界中的實體(例如人、車子、電視、房子、衣服、長方形等等)。在真實世界中,一個實體具有屬性和行為,舉例來說,一個人的屬性包括年齡、身高、體重、姓名等等,行為包括走路、吃飯、睡覺、說話等等。因此,物件也具有屬性和行為。 (2)物件和類別的關係,好比真實世界中,房子和建築設計圖的關係。建築設計圖決定房子應該怎麼蓋,也就是說,房子是根據建築設計圖的設計來建造的,房子是建築設計圖的實例。因此,類別會定義物件的屬性和行為,物件是透過類別建立出來的,物件是類別的實例。物件的屬性和行為分別用欄位(實例變數)和方法來描述。 (3)一個類別可以被用來建立許多物件。假設有某些物件是由相同的類別建立的,那麼這些物件會擁有共同的屬性和行為。舉例來說,假設有一個名稱為Human的類別,那麼Human會包含的欄位有age、height、weight、name等等,因為這些屬性是所有Human的實例共同擁有的(好比真實世界中,所有人都是「人類」的實例,年齡、身高、體重、姓名是所有人共同擁有的屬性)。所以簡單來說,類別就是物件的藍圖,擁有相同特性的物件可以集合起來,歸類為同一個類別。 (4)欄位的值代表物件的狀態,可以隨著時間不同而改變,好比真實世界中,剛出廠的新款襯衫價格是1000元,但過了一陣子,因為款式相對變舊了,所以價格變為500元,開始對折出清。 (5)物件的行為可能會改變其狀態。舉例來說,假設有一個名稱為TV的類別,如下圖所示,它定義的欄位包括channel、volumeLevel和on,方法包括turnOn、turnOff、setChannel、setVolume、channelUp、channelDown、volumeUp和volumeDown,這些方法都有可能會改變欄位的值。
imgur
(6)物件是實際存在的東西,所以Java會為物件配置記憶體空間;類別只定義了物件擁有哪些屬性和行為,它是「物件架構的描述」,並非實際存在的東西,所以Java不可能為這種抽象的東西分配記憶體空間。另外要注意的是,物件是在程式「執行」時建立的,舉例來說,假設有一個類別叫做Student,它有無參數的建構子,當我們寫下「new Student( )」的時候,物件還不會建立,要等到程式執行「new Student( )」的時候,Java才會建立Student的物件,並在heap memory為其分配空間。 31.什麼是物件導向? 解答: (1)物件導向模擬真實世界,真實世界中的東西會彼此互動,舉例來說,學生彈鋼琴,就是學生和鋼琴在互動,所以物件之間也需要互動,使用的媒介就是「訊息」。 (2)實際上,物件導向真正的核心概念是訊息,而不是物件。物件是使用訊息來模擬彼此之間的互動,換言之,訊息是物件之間的溝通橋樑。訊息可說是物件運作的動力來源,沒有了訊息,物件的存在是沒有意義的,就像人如果無法和外界溝通,那麼和植物人沒什麼兩樣,所以訊息是物件不可或缺的一項特性。若一個物件向另一個物件發送訊息,代表前者(sender)要求後者(receiver)執行某個指定的方法。透過處理訊息,物件(receiver)的狀態可能會改變。
imgur
(3)物件(receiver)是依照接收到的訊息來執行方法,而訊息會包含三種資訊:哪個物件是receiver(訊息要被哪個物件處理)、receiver要執行的方法名稱和參數,只需有差異就足以讓receiver辨識出是不同的方法,所以方法同名也沒關係,只要參數個數不同或型態不同,對於receiver來說,已經足以從訊息判斷出是要執行哪個方法,這種機制稱為「方法多載(method overloading)」。 (4)針對同一個訊息,不同的物件(receiver)會有不同的處理方式,稱為「多型」;物件只能互相發送訊息,看不到彼此的內部狀態,稱為「封裝」。 (5)另外,物件導向只是一種「程式設計的方式或風格」,所以它不應該被視為程式語言的特性,換言之,不應該把Java歸類為「物件導向程式語言」,因為Java也可以用來做不是物件導向的程式設計,Java只不過是「易於實作物件導向」的程式語言。總而言之,程式語言不應該依照「它能寫出什麼風格的程式碼」來歸類,而是「它對那種風格的程式碼提供了多少語法支援」。 32. 什麼是建構子? 解答: (1)建構子是一種特殊的方法,當物件被建立時,建構子就會被呼叫。建構子通常用來設定欄位的初始值。 (2)建構子的宣告不能有return type或void,不過建構子會自動回傳物件本身。 33. 說明建構子和方法的差別。 解答: (1)方法是用來描述物件的行為,而建構子則通常用來初始化物件的狀態。 (2)方法的宣告必須有return type或void,但建構子的宣告不能有return type或void。 (3)如果類別內沒有任何方法,Java不會提供預設的方法;如果類別內沒有任何建構子,Java會提供一個預設的無參數建構子。 (4)方法的名稱不一定要跟類別的名稱相同,但建構子的名稱一定要跟類別的名稱相同。 (5)方法只能由程式設計者「手動」呼叫,但建構子除了可以透過this或super來手動呼叫,透過new來建立物件時,系統會「自動」呼叫建構子。 (6)方法可以被繼承,但建構子不能。 (7)方法可以用public、private、protected、static、final、abstract、synchronized、native和strictfp來修飾,但建構子能用的修飾詞只有public、private和protected。 (8)方法和建構子都可以使用多載。 34. 下圖中的Test類別能不能被實例化?
imgur
解答: (1)當一個類別被實例化時,流程如圖43所示。關於這個部分,JLS的12.5節有更詳盡的說明,圖44展示的是該小節提供的一個重要範例。 (圖43)
imgur
(圖44)
imgur
(3)下面列出更多相關的簡單例子。
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
(3)如果將本題的Test類別實例化,Java會先為物件分配記憶體空間,並賦予所有實例變數預設值,接著呼叫建構子,隨後呼叫Object類別的無參數建構子,並將Object類別的所有實例變數初始化,然後回到Test類別,執行t的初始化,這時Test類別再度被實例化……,如此不斷的遞迴下去,所以程式執行時會發生錯誤(StackOverflowError)。 35. 下圖中的程式會輸出什麼內容?
imgur
解答: main方法呼叫無參數的建構子,無參數的建構子先呼叫有一個參數的建構子(Test(int i)),再印出Hi,而Test(int i)先呼叫有兩個參數的建構子(Test(int i, int j)),印出"How are you? ",再印出"Hello",所以程式會印出下圖中的結果。
imgur
36. 下圖中的程式會輸出什麼內容?
imgur
解答: (1)整數的字面常數預設的資料型態是int,所以main方法呼叫的是第3個test方法。 (2)如果將本題的程式改成下圖中的樣子,Java就找不到參數型別符合引數型別(int)的test方法了,這時它會「向上尋找」,第一個找的是參數型別為long的test方法。下圖中的程式剛好有test(long i),故Java會呼叫test(long i),而不是test(Integer i)。
imgur
(3)延續第2點的說明,假設test方法被overload,若呼叫test方法時傳入的引數型別是int,Java尋找test方法的順序是:test(int i)→test(long i)→test(float i)→test(double i)→test(Integer i)→test(Object i)→test(int... i)→test(long... i)→test(float... i)→test(double... i),也就是說,Java首先會去找test(int i),如果有找到,就呼叫它,否則就去找test(long i),如果有找到,就呼叫它,否則就繼續去找test(float i),依此類推。 37. 下圖中的程式會輸出什麼內容?
imgur
解答: 根據上一題的第3點說明,main方法呼叫的是test(long i)。 38. 下圖中的程式會輸出什麼內容?
imgur
解答: 根據第36題的第3點說明,可以看出一個原則,Varargs的方法一定優先度最低,而向上轉型一定比裝箱(boxing)優先,所以在本題的程式當中,main方法呼叫的是test(long l, short s)。 39. 下圖中的程式會輸出什麼內容?
imgur
解答: (1)先舉個例子,如下圖所示,因為B是A的子類別,所以Java會選擇呼叫test(B b)。
imgur
(2)如下圖所示,如果將上圖中的程式改成這樣,Java就不知道該呼叫哪個方法了。
imgur
(3)在本題的程式當中,由於String是Object的子類別,所以main方法呼叫的是test(String i)。 (4)如圖45所示,如果將本題的程式改成這樣,String和StringBuffer都是Object的子類別,但Java無法從test(String i)和test(StringBuffer i)當中選出要呼叫的方法,所以就會發生編譯錯誤。如果要避免這種模稜兩可的情形,應該明確指定null是屬於什麼型別,好讓Java知道要呼叫哪個方法,如圖46和圖47所示。 (圖45)
imgur
(圖46)
imgur
(圖47)
imgur
(5)下面再舉更多方法多載時null作為引數的例子,僅供參考。
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
imgur
40. main方法可不可以被overload? 解答: (1)作為程式進入點的main方法必須符合兩個條件:第一,其宣告必須符合"public static void main"(或"static public void main")的形式;第二,其參數必須是字串陣列。圖48、圖49和圖50當中的方法簽章(method signature)都符合main方法作為程式進入點的條件。 (圖48)
imgur
(圖49)
imgur
(圖50)
imgur
(2)另外,作為程式進入點的main方法還可以再用final、synchronized或strictfp來修飾,如下方的四張圖所示。由於public、static、final、synchronized和strictfp都是Java的修飾詞,所以不管它們怎麼調換位置,都不會影響main方法的意義。
imgur
imgur
imgur
imgur
(3)main方法就跟一般的方法一樣可以被overload,不過要注意的是,如果程式當中沒有可作為進入點的main方法,執行時會發生錯誤,如下方的三張圖所示。
imgur
imgur
imgur
(4)相關的內容可參考part 1的第4題。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 本篇的正文已同步放到Notion了👇👇,如果Dcard的排版讓你看得很頭痛,建議到Notion觀看哦~
愛心跪
43
留言 2
文章資訊