程序員電話面試題匯總大全(2)
程序員電話面試題匯總大全
19. 組合(composition),聚合(aggregation)和關(guān)聯(lián)(association)的區(qū)別是什么? (detailed answer)
關(guān)聯(lián)的意思是兩個(gè)對象是相互聯(lián)系的。組合是關(guān)聯(lián)的一種形式,即一個(gè)對象由多個(gè)對象組成,但是它們必須共存,例如人體由各種器官組合而成,獨(dú)立的器官不能生存,它們必須在身體內(nèi)發(fā)揮作用。聚合也是關(guān)聯(lián)的一種形式,表示對象的集合,例如城市是居民的聚合。
20. 接口和抽象類有什么區(qū)別? (detailed answer)
這是所有程序員面試最經(jīng)典的問題。接口是最純粹的抽象形式,沒有任何具體的東西。抽象類是一些抽象和具體事物的組合體。這個(gè)區(qū)別在不同語言中可能會不同,例如在Java中你可以擴(kuò)展(extend)多個(gè)接口,但只能繼承一個(gè)抽象類。更詳細(xì)的討論見于詳細(xì)答案。
21. 什么是單元測試?(answer)
單元測試是測試獨(dú)立單元(而不是整個(gè)應(yīng)用程序)功能性的一種方法。在不同語言中,有很多工具可以做單元測試。例如在Java中,你可以用JUnit或TestNG來寫單元測試。單元測試經(jīng)常在構(gòu)建時(shí)自動(dòng)運(yùn)行,或者在一個(gè)持續(xù)的環(huán)境(例如Jenkins)中運(yùn)行。
22. 你能否描述三種不同的在應(yīng)用程序發(fā)布前對其進(jìn)行測試的方式?
單元測試,集成測試,冒煙測試。單元測試用來測試獨(dú)立的單元是否依照預(yù)期工作,集成測試用來測試已被測試過的獨(dú)立單元能否共同工作,冒煙測試用來測試軟件最常用的功能是否正常工作,例如在一個(gè)飛機(jī)訂票網(wǎng)站中,你應(yīng)該能訂票,取消或更改航班。
23. 迭代和遞歸有什么區(qū)別?(detailed answer)
迭代通過循環(huán)來重復(fù)執(zhí)行同一步驟,遞歸通過調(diào)用函數(shù)自身來做重復(fù)性工作。遞歸經(jīng)常是復(fù)雜問題(例如漢諾塔、反轉(zhuǎn)鏈表或反轉(zhuǎn)字符串)的清晰簡潔的解決方案。遞歸的一個(gè)缺陷是深度,由于遞歸在棧中存儲中間結(jié)果,你只能進(jìn)行一定深度的遞歸,在那之后你的程序會因?yàn)镾tackOverFlowError而崩潰。這就是在產(chǎn)品代碼中優(yōu)先使用迭代而不是遞歸的原因。
24. &和&&運(yùn)算符的區(qū)別是什么?(detailed answer)
&是位運(yùn)算符,&&是邏輯運(yùn)算符。&和&&的一個(gè)區(qū)別是位運(yùn)算符(&)可以被用于整型和布爾類型,邏輯運(yùn)算符(&&)只能被用于布爾類型變量。當(dāng)你寫a & b時(shí),兩個(gè)整型數(shù)的每一位都會進(jìn)行與運(yùn)算。當(dāng)你寫a && b時(shí),第二個(gè)參數(shù)可能會也可能不會被執(zhí)行,這也是它被稱為短路運(yùn)算符的原因,至少在Java中是這樣的。我很喜歡這個(gè)問題,經(jīng)常對初級開發(fā)者和畢業(yè)生問這個(gè)問題。
25. 1 XOR 1的結(jié)果是什么?
答案是0,因?yàn)閄OR在兩個(gè)操作數(shù)(按位)不同時(shí)返回1,相同時(shí)返回0。例如0 XOR 0仍然是零,但0 XOR 1和1 XOR 0的結(jié)果是1。
26. 如何得到一個(gè)整型數(shù)的最后一位? (answer)
用取模運(yùn)算符,數(shù)字 % 10返回?cái)?shù)字的最后一位。例如2345 % 10會返回5,567 % 10會返回7。類似的,除運(yùn)算符可以用來去掉數(shù)字的最后一位,例如2345 / 10的結(jié)果是234,567 / 10的結(jié)果是56。這是值得了解的一個(gè)重要技巧,可以用來解決類似回文數(shù)、反轉(zhuǎn)數(shù)的問題。
27. 什么是測試驅(qū)動(dòng)開發(fā)?
測試驅(qū)動(dòng)是一種常見的開發(fā)方法,在這種方法中,測試代碼在功能代碼之前編寫。測試決定了程序的結(jié)構(gòu)。測試驅(qū)動(dòng)的純粹主義者在寫為應(yīng)用寫測試之前,不會寫一行的應(yīng)用代碼。這能很大幅度地提高代碼質(zhì)量,經(jīng)常被認(rèn)為是巨星級開發(fā)者的品質(zhì)。
28. 里氏替換原則(Liskov substitution principle, LSP)是什么?(answer)
里氏替換原則是鮑勃大叔稱作SOLID的五條設(shè)計(jì)原則中的一條。里氏替換原則規(guī)定,所有的子類都能作為父類的代理(proxy)工作。例如,如果一個(gè)方法需要父類對象作為輸入,那么如果你提供一個(gè)子類對象,它也應(yīng)該正常工作。任何不能替代父類的類都違反了里氏替換原則。這實(shí)際上是一個(gè)難以答出的問題,如果你答出了,那么就會給面試官留下好的印象。
29. 什么是開閉(Open closed)設(shè)計(jì)原則?(answer)
開閉原則是SOLID中另一個(gè)重要的原則,它規(guī)定一個(gè)系統(tǒng)對擴(kuò)展是開放的,但對修改是封閉的。意思是說,如果一個(gè)新的功能要被加入一個(gè)穩(wěn)定的系統(tǒng),那么你不需要碰已被測試過的現(xiàn)有代碼,新的功能可以通過只添加新類來實(shí)現(xiàn)。
30. 二叉樹和二叉查找樹的區(qū)別是什么?
二叉查找樹是有序的二叉樹,所有節(jié)點(diǎn)(例如根節(jié)點(diǎn))的左子樹節(jié)點(diǎn)的值都小于或等于該節(jié)點(diǎn)的值,右子樹節(jié)點(diǎn)的值都大于或等于該節(jié)點(diǎn)的值。它是一個(gè)重要的數(shù)據(jù)結(jié)構(gòu),可以用來表示有序的數(shù)據(jù)。
31. 你能否給出一個(gè)遞歸算法的實(shí)際例子?(example)
遞歸算法能適用在很多地方,例如與二叉樹和鏈表相關(guān)的算法。幾個(gè)與遞歸算法的例子包括反轉(zhuǎn)字符串,計(jì)算斐波那契數(shù)列。其他的例子包括反轉(zhuǎn)鏈表、樹遍歷以及快速排序。
31. 算法的時(shí)間復(fù)雜度是什么?
時(shí)間復(fù)雜度表示的是運(yùn)行時(shí)間對輸入量的比率。他表示一個(gè)算法處理一定量的輸入需要多長時(shí)間。它是一個(gè)估計(jì)值,但足夠表示輸入量從十增長到一千萬時(shí),你的算法會有什么樣的表現(xiàn)。
33. 鏈表和數(shù)組有哪些重要區(qū)別?(detailed answer)
鏈表和數(shù)組都是程序設(shè)計(jì)世界中重要的數(shù)據(jù)結(jié)構(gòu)。它們間最明顯的區(qū)別是,數(shù)組將元素存放在連續(xù)的地址中,鏈表將數(shù)據(jù)存放在內(nèi)存中任意的位置。這使得鏈表有巨大的擴(kuò)展自己的靈活性,因?yàn)閮?nèi)存總是分散的。這種情況總是可能的:你無法創(chuàng)建一個(gè)數(shù)組來存放一百萬個(gè)整數(shù),但可以用鏈表來存放,因?yàn)榭臻g是存在的,只是不連續(xù)。其他的不同都是源于這項(xiàng)事實(shí)。例如,在數(shù)組中,如果你知道下標(biāo),可以用O(1)的時(shí)間得到一個(gè)元素,但在鏈表中要花O(n)的時(shí)間。更多不同參見詳細(xì)答案。
33. 在哈希表中處理沖突的方法都有哪些?
線性探測(linear probing),二次哈希(double hashing)和鏈接(chaining)。在線性探測中,如果桶已經(jīng)被占據(jù)了,那么函數(shù)會線性地檢查下一個(gè)桶,直到找到一個(gè)空位。在鏈接中,多個(gè)元素可以存儲在同一個(gè)桶中。
34. 正則表達(dá)式是什么意思? (answer)
正則表達(dá)式是在文本型數(shù)據(jù)上進(jìn)行模式匹配的方法。它是一種搜索的強(qiáng)有力方法,例如搜索長字符串中的某些字符,例如搜索一本書中是否含有某個(gè)單詞。所有主流程序設(shè)計(jì)語言都支持正則表達(dá)式,但是Perl正則表達(dá)式的能力是著名的。Java的java.util.regex包也支持類似Perl的正則表達(dá)式。你可以用正則表達(dá)式檢查email地址是否有效,電話號碼是否有效,郵政編碼是否有效,甚至社會保險(xiǎn)號(SSN)是否有效。正則表達(dá)式最簡答的例子之一是檢查字符串是不是一個(gè)數(shù)。
35. 什么是無狀態(tài)(stateless)系統(tǒng)?
無狀態(tài)系統(tǒng)是不維護(hù)內(nèi)部狀態(tài)的系統(tǒng)。這種系統(tǒng)在任何時(shí)刻,對相同的輸入都會給出相同的輸出。編寫優(yōu)化一個(gè)無狀態(tài)系統(tǒng)總是比較簡單的,所以如果可能,你總是應(yīng)該優(yōu)先編寫無狀態(tài)系統(tǒng)。
36. 寫一個(gè)SQL查詢,在雇員表中查找第二高的工資。 (solution)
這是SQL面試的經(jīng)典題目之一,盡管已經(jīng)很老了,還是很有趣,并且可以追問很多問題來測試候選人的知識深度。你可以用相關(guān)或不相關(guān)的子查詢來查找第二高工資。如果你在用SQL Server或MySQL,你也可以用類似TOP和LIMIT之類的關(guān)鍵字,前提是面試官允許。查找第二高工資的最簡答方法是:
這個(gè)查詢首先查找最高工資,然后將它從列表中排除,再查找最高工資。很明顯,第二次返回的是第二高工資。
37. 可否描述一下什么是關(guān)聯(lián)的和不關(guān)聯(lián)的子查詢?(answer)
在關(guān)聯(lián)的子查詢中,內(nèi)層查詢依賴于外層查詢,對外層查詢的每一行執(zhí)行。非關(guān)聯(lián)的子查詢不依賴于外層查詢,可以獨(dú)立執(zhí)行。因此,前者慢,后者快。順便說一下,關(guān)聯(lián)的子查詢有一些很棒的應(yīng)用,其中包括在雇員表中查找第N高的工資,這在上一道SQL問題中也有提到。
39. 不用算術(shù)運(yùn)算符,如何判定一個(gè)數(shù)是否是二的冪?(solution)
當(dāng)你聽到不能用算術(shù)運(yùn)算符的限制時(shí),應(yīng)該立刻假定這是一道關(guān)于位運(yùn)算的題。如果沒有這條限制,那么你可以輕松地用取模和除運(yùn)算符檢查一個(gè)數(shù)是不是二的冪。用位運(yùn)算符,有一個(gè)很巧妙的方法來完成任務(wù)。你可以用下面這段代碼來檢查一個(gè)數(shù)是不是二的冪
1 2 3 | public static boolean powerOfTwo( int x) { return (x & (x - 1 )) == 0 ; } |
x & (x-1)是一個(gè)很棒的技巧,可以將最右邊的為1的位設(shè)為0。我是從《高效程序的奧秘》這本書中學(xué)到的。
40. 如何在UNIX上找到一個(gè)正在運(yùn)行的Java進(jìn)程?(command)
你可以組合使用ps和grep命令來查找UNIX機(jī)器上的任何進(jìn)程。假設(shè)你的Java進(jìn)程有名字,或者有任何可以用來匹配的文字,那么使用這個(gè)命令。
ps -ef | grep “myJavaApp”
ps -e將列出所有的進(jìn)程(所有用戶的進(jìn)程,不只是你的),ps -f將顯示所有細(xì)節(jié),包括PID。如果你想要深入調(diào)查或用kill命令殺死這個(gè)進(jìn)程,你會需要PID。
41. 如何在UNIX中尋找大的文件,例如1GB以上的文件? (command)
你可以輕松地用find命令尋找大的文件,因?yàn)樗峁┮罁?jù)大小尋找文件的選項(xiàng)。如果你的文件系統(tǒng)滿了,你的Java進(jìn)程因?yàn)闆]有空間而崩潰,那么就使用這個(gè)命令。這個(gè)命令可以列出所有大于1GB的文件。你可以很容易地改變大小,例如尋找所有100MB以上的文件,就用+100M。
find . – type f -size +1G -print
42. shell腳本是什么?
shell腳本是包含程序元素(例如if和for循環(huán))的一組shell命令,它可以自動(dòng)做一些重復(fù)的任務(wù)。例如,你可以寫一個(gè)shell腳本來每天清理日志文件,為記錄歷史備份數(shù)據(jù),以及其他家務(wù)活、版本發(fā)布、監(jiān)視等等。