詳細解析
今年是2015年,在過去幾年中,電面(電話面試)是挑選程序員職位候選人的最流行的方式。它讓雇傭雙方很容易相互了解對方,候選人不需要去未來雇主的所在地,面試官也不用做額外的安排。這是我介紹程序員面試問題的文章的第2部份。我得到反饋說第1部份過于偏重編碼的題了,許多程序員希望我針對電面問題列1個類似的列表。為了順利通過電面進入下1輪,你必須足夠好地回答與你工作要求相干的全部問題。在大多針對Java
和C++
開發者的電面中,你不但會遇到相應程序語言的問題,還會遇到其他技術的問題,比如SQL
、XML
、UNIX
、泛型編程、面向對象編程、數據結構與算法、網絡、編碼和工作的其他方面。由于程序員求職電面的多變性,你需要有特殊的技能,以面試官期待的方式展現自己。
要記住1件重要的事,在回答電面問題的時候,盡早提出關鍵點,總是給出關鍵性回答。由于面試官的問題常常會覆蓋很大范圍的主題,他們更喜歡關鍵性回答,而不是OK,我知道
之類的空話。在面對面的面試中,你會有機會更深入地解釋問題的。順便說1下,這其實不是固定的規則,根據面試官對你的回答的反應,你可以了解到他期望得到甚么樣的回答。如果他進行追問,期望你多說1些,那末你就應當多說。但如果他立刻跳到下1個問題,那末你就應當回答得清晰簡潔。在這篇文章中,我要和你分享1些常見的有趣編程問題,它們是針對電面改編過的。其中大部份都來自科技公司的電面環節,包括Barclays
、Citi
、Nomura
之類的銀行,和Infosys
、TCS
、CTS
、Tech Mahindra
和HCL
之類的提供服務的公司。像我之條件過的,面試題是隨機選的,但大部份是基于基礎知識,由于那是面試官在電面時想考察的。雖然這些問題大多數是針對低級開發者(2至5年經驗),高級和資深程序員依然可以把它們用作自己面試的題目。如果你是1名面試官,你可以用這些問題快速挑選開發職位的候選人。我在此提供簡短答案,并給出詳細答案的鏈接。
下面是幾近50
道程序員電面題目的列表。這些問題可以用來考察任何程序員、開發者、軟件工程師、測試和運營工程師,由于它們是基于程序設計的基礎知識的。但它們最合適程序員和開發者。順便說1下,如果你是Java
開發者,并且在尋覓Java
電面題目,去看看那個列表。本列表更加普遍,適用于所有的程序員,包括Python
、Ruby
、Perl
和C#
開發者。
1.從哈希表,2叉樹和鏈表中取元素需要多少時間?如果你有數百萬記錄呢?
哈希表需要O(1)
時間,2叉樹需要O(logN)
(N
是樹中節點數),鏈表需要O(N)
(N
是鏈表中節點數)。如果數據結構工作正常(比如哈希表沒有或只有相對少許沖突,2叉樹是平衡的),數百萬記錄其實不影響效力。如果工作不正常,那末效力會隨著記錄數上升而降落。
2.覆蓋(Overriding
)和重載(Overloading
)的區分是甚么? detailed answer
覆蓋在運行時決定,重載是在編譯時決定。并且覆蓋和重載的機制不同,例如在Java
中,private
3.fork
1個進程和生成1個線程有甚么區分?
當你fork
1個進程時,新的進程將履行和父進程相同的代碼,只是在不同的內存空間中。但當你在已有進程中生成1個線程時,它會生成1個新的代碼履行線路,但同享同1個內存空間。
4.甚么是臨界區? answer
臨界區是1段代碼,10分重要,在多線程中同1時間只能被1個線程履行。可以用信號量或互斥量來保護臨界區。在Java
中你可以用synchronized
關鍵字或ReentrantLock
來保護臨界區。
5.值類型和援用類型有甚么區分? answer
值類型是更加優化的類型,總是不可變的(immutable
),例如Java
原始的int
、long
、double
和float
。援用類型指向1個對象,多是可變的,也多是不變的。你也能夠說值類型指向1個值,援用類型指向1個對象。
6.甚么是在進程中的堆和棧?
在同1個進程中,有兩塊不同的內存區域。以Java
來講,棧用來存儲原始值和指向對象的援用類型,但對象本身總是在堆中被創建。堆和棧的1個重要區分是,堆內存被所有線程同享,但每一個線程有自己的棧。
7.甚么是版本控制?
版本控制是用來存儲代碼和管理代碼庫版本的軟件,例如SVN
、CVS
、Git
、Perforce
和ClearCase
。它們在對照代碼、審查代碼和從之前的穩定版本構造時10分高效。所有的專業開發都使用某種版本控制工具,否則你沒法有效的管理代碼,特別是如果有20個開發者在同1個代碼庫上工作的時候。版本控制工具在保持代碼庫1致性和處理代碼沖突上扮演著10分重要的角色。
8.甚么是強類型程序設計語言?
在強類型語言中,編譯器確保類型的正確性,例如你沒法在String
類型中寄存數字,反之亦然。Java
是強類型語言,因此存在各種數據類型(如int
、float
、String
、char
、boolean
等)。你只能將兼容的值存入相應的類型中。與此相反,弱類型語言不要求在編譯時進行類型檢查,它們根據上下文處理值。Python
和Perl
是兩個常見的弱類型程序設計語言的例子,你可以將數字組成的字符串保存在數字類型中。
9.可否描寫1下有效(valid
)的XML
和格式正確(well-formed
)的XML
的區分?
格式正確的XML
有根元素,所有標簽都是正確關閉的,屬性是正肯定義的,它們的值正確地加上了引號。另外一方面,有效的XML
可以根據1個XSD
文件或模式(schema
)進行驗證。所以1個XML
多是格式正確但不有效的(由于包括不被模式允許的標簽)。
10.DOM
和SAX
語法分析器有甚么區分?
DOM
語法分析器是駐留內存的,將全部XML
文件裝載到內存中,并創建1個DOM
樹進行語法分析。SAX
語法分析器是1個基于事件的語法分析器,所以它根據收到的事件(如開始標簽、結束標簽、屬性開始和屬性結束)來對XML
文檔進行語法分析。根據他們的分析方法,DOM
語法分析器其實不適用于大的XML
文件,由于它會占用大量的內存空間,你的進程可能會耗盡內存。應當用SAX
分析大的文件。對小的文件,DOM
常常比SAX
快很多。
11.線程和進程的關系是甚么?
1個進程可以有多個線程,但1個線程總是屬于唯1的進程。兩個進程不能同享內存空間,除非它們成心通過同享內存進行進程間通訊。但是同1進程的兩個線程總是同享相同的內存。
12.不可變(immutable
)類是甚么意思?
1個類,如果在創建以后它的狀態就不能被改變,那末他就是不可變的。例如Java
中的String
。1旦你創建了1個String
,例如Java
,你就不能再改變它的內容。任何對這個字符串的改變(例如轉換到大寫、與另外一個String
連接)將創建1個新的對象。不可變的對象在并行程序設計中很有用,由于它們可以在進程間被同享,不需要擔心同步。事實上,全部函數是程序設計的模型都是在不可變對象上構建的。
13.你為什么要創建摹擬(mock
)對象?
摹擬對象在測試軟件中1個獨立的單元時很有用,事實上,存根(stub
)和摹擬都是創建自動化單元測試的有力工具。假定你在寫1個顯示貨幣兌換率的程序,但沒有1個可以連通的URL
,現在如果想測試你的代碼,可以用摹擬對象。在Java
的世界中,有很多框架可以為你生成強大的摹擬對象,例如Mockito
和PowerMock
。
14.甚么是SQL
注入?
SQL
注入是1種安全漏洞,它使得入侵者可以從系統中盜取數據。任何從用戶那里得到輸入其實不加驗證地創建SQL
查詢的系統都可能被SQL
注入攻擊。在這樣的系統中,入侵者可以輸入SQL
代碼,而不是數據,來獲得額外的數據。有很多用敏感信息(如用戶id
、密碼和個人信息)被人利用這類漏洞獲得的實例。 在Java
中,你可以用Prepared
語句來避免SQL
注入。
15.在SQL
中,內連接(inner join
)和左連接(left join
)有甚么區分?
在SQL
中,主要有兩種連接類型,內連接和外連接。外連接包括右外連接和左外連接。內連接和左連接的主要區分是,內連接中兩個表都匹配的記錄才被選中,左連接中兩個表都匹配的記錄被選中,外加左表的所有記錄都被選中。要留意包括“所有”的查詢,它們常常要求左連接,例如寫1個SQL
查詢來找所有的部門和它們的雇員人數。如果你用內連接處理這個查詢,你會漏掉沒有人工作的空部門。
16.MVC
中的V
代表甚么,意味著甚么?
在MVC
模式中,V
是視圖(View
)。視圖是用戶看到的東西,比如網頁。這是1個非常重要的web
利用開發設計模式,它基于關注點分離原則,目的是不同模塊可以獨立修改,不影響其他模塊。在Java
的世界中,有很多提供MVC
模式的開源框架,例如Struts 2
和Spring MVC
。順便說1下,M
代表模型(Model
),C
代表控制器(Controller
)。模型是實際的業務對象,例如用戶、雇員、定單,控制器用來將要求分發給正確的處理單元。
17.類和對象的區分是甚么?
類是用來創建對象的設計圖。1個類包括代碼和行動,1個對象包括狀態和行動。要創建1個對象,你必須創建1個表達對象結構的類。類還被用來在內存中映照對象,在Java
中,JVM
替你完成這項工作。
18.甚么是疏耦合(loose-coupling
)?
疏耦合是1種值得尋求的軟件特性,它使得對軟件1個部份的修改不會影響到其他的部份。例如,在1個疏耦合的軟件中,對UI
布局的改變不應當影響后真個類結構。
19.組合(composition
),聚合(aggregation
)和關聯(association
)的區分是甚么?
關聯的意思是兩個對象是相互聯系的。組合是關聯的1種情勢,即1個對象由多個對象組成,但是它們必須共存,例如人體由各種器官組合而成,獨立的器官不能生存,它們必須在身體內發揮作用。聚合也是關聯的1種情勢,表示對象的集合,例如城市是居民的聚合。
20.接口和抽象類有甚么區分?
這是所有程序員面試最經典的問題。接口是最純潔的抽象情勢,沒有任何具體的東西。抽象類是1些抽象和具體事物的組合體。這個區分在不同語言中可能會不同,例如在Java
中你可以擴大(extend
)多個接口,但只能繼承1個抽象類。更詳細的討論見于詳細答案。
21.甚么是單元測試?
單元測試是測試獨立單元(而不是全部利用程序)功能性的1種方法。在不同語言中,有很多工具可以做單元測試。例如在Java
中,你可以用JUnit
或TestNG
來寫單元測試。單元測試常常在構建時自動運行,或在1個延續的環境(例如Jenkins
)中運行。
22.你能否描寫3種不同的在利用程序發布前對其進行測試的方式?
單元測試,集成測試,冒煙測試。單元測試用來測試獨立的單元是不是依照預期工作,集成測試用來測試已被測試過的獨立單元能否共同工作,冒煙測試用來測試軟件最經常使用的功能是不是正常工作,例如在1個飛機訂票網站中,你應當能訂票,取消或更改航班。
23.迭代和遞歸有甚么區分?
迭代通過循環來重復履行同1步驟,遞歸通過調用函數本身來做重復性工作。遞歸常常是復雜問題(例如漢諾塔、反轉鏈表或反轉字符串)的清晰簡潔的解決方案。遞歸的1個缺點是深度,由于遞歸在棧中存儲中間結果,你只能進行1定深度的遞歸,在那以后你的程序會由于StackOverFlowError
而崩潰。這就是在產品代碼中優先使用迭代而不是遞歸的緣由。
24.&
和&&
運算符的區分是甚么?
&
是位運算符,&&
是邏輯運算符。&
和&&
的1個區分是位運算符(&
)可以被用于整型和布爾類型,邏輯運算符(&&
)只能被用于布爾類型變量。當你寫a & b
時,兩個整型數的每位都會進行與運算。當你寫a && b
時,第2個參數可能會也可能不會被履行,這也是它被稱為短路運算符的緣由,最少在Java
中是這樣的。我很喜歡這個問題,常常對低級開發者和畢業生問這個問題。
25.1 XOR 1
的結果是甚么?
答案是0
,由于XOR
在兩個操作數(按位)不同時返回1,相同時返回0。例如0 XOR 0
依然是零,但0 XOR 1
和1 XOR 0
的結果是1。
26.如何得到1個整型數的最后1位?
用取模運算符,數字 % 10
返回數字的最后1位。例如2345 % 10
會返回5
,567 % 10
會返回7
。類似的,除運算符可以用來去掉數字的最后1位,例如2345 / 10
的結果是234
,567 / 10
的結果是56
。這是值得了解的1個重要技能,可以用來解決類似回文數、反轉數的問題。
27.甚么是測試驅動開發?
測試驅動是1種常見的開發方法,在這類方法中,測試代碼在功能代碼之前編寫。測試決定了程序的結構。測試驅動的純潔主義者在寫為利用寫測試之前,不會寫1行的利用代碼。這能很大幅度地提高代碼質量,常常被認為是巨星級開發者的品質。
28.里氏替換原則(Liskov substitution principle
, LSP
)是甚么?
里氏替換原則是鮑勃大叔稱作SOLID
的5條設計原則中的1條。里氏替換原則規定,所有的子類都能作為父類的代理(proxy
)工作。例如,如果1個方法需要父類對象作為輸入,那末如果你提供1個子類對象,它也應當正常工作。任何不能替換父類的類都違背了里氏替換原則。這實際上是1個難以答出的問題,如果你答出了,那末就會給面試官留下好的印象。
29.甚么是開閉(Open closed
)設計原則?
開閉原則是SOLID
中另外一個重要的原則,它規定1個系統對擴大是開放的,但對修改是封閉的。意思是說,如果1個新的功能要被加入1個穩定的系統,那末你不需要碰已被測試過的現有代碼,新的功能可以通過只添加新類來實現。
30.2叉樹和2叉查找樹的區分是甚么?
2叉查找樹是有序的2叉樹,所有節點(例如根節點)的左子樹節點的值都小于或等于該節點的值,右子樹節點的值都大于或等于該節點的值。它是1個重要的數據結構,可以用來表示有序的數據。
31.你能否給出1個遞歸算法的實際例子?
遞歸算法能適用在很多地方,例如與2叉樹和鏈表相干的算法。幾個與遞歸算法的例子包括反轉字符串,計算斐波那契數列。其他的例子包括反轉鏈表、樹遍歷和快速排序。
32.算法的時間復雜度是甚么?
時間復雜度表示的是運行時間對輸入量的比率。他表示1個算法處理1定量的輸入需要多長時間。它是1個估計值,但足夠表示輸入量從10增長到1千萬時,你的算法會有甚么樣的表現。
33.鏈表和數組有哪些重要區分?
鏈表和數組都是程序設計世界中重要的數據結構。它們間最明顯的區分是,數組將元素寄存在連續的地址中,鏈表將數據寄存在內存中任意的位置。這使得鏈表有巨大的擴大自己的靈活性,由于內存總是分散的。這類情況總是可能的:你沒法創建1個數組來寄存1百萬個整數,但可以用鏈表來寄存,由于空間是存在的,只是不連續。其他的不同都是源于這項事實。例如,在數組中,如果你知道下標,可以用O(1)
的時間得到1個元素,但在鏈表中要花O(n)
的時間。更多不同參見詳細答案。
34.在哈希表中處理沖突的方法都有哪些?
線性探測(linear probing
),2次哈希(double hashing
)和鏈接(chaining
)。在線性探測中,如果桶已被占據了,那末函數會線性地檢查下1個桶,直到找到1個空位。在鏈接中,多個元素可以存儲在同1個桶中。
35.甚么是無狀態(stateless
)系統?
無狀態系統是不保護內部狀態的系統。這類系統在任什么時候刻,對相同的輸入都會給出相同的輸出。編寫優化1個無狀態系統總是比較簡單的,所以如果可能,你總是應當優先編寫無狀態系統。
36.寫1個SQL
查詢,在雇員表中查找第2高的工資。
這是SQL
面試的經典題目之1,雖然已很老了,還是很有趣,并且可以追問很多問題來測試候選人的知識深度。你可以用相干或不相干的子查詢來查找第2高工資。如果你在用SQL Server
或MySQL
,你也能夠用類似TOP
和LIMIT
之類的關鍵字,條件是面試官允許。查找第2高工資的最簡答方法.這個查詢首先查找最高工資,然后將它從列表中排除,再查找最高工資。很明顯,第2次返回的是第2高工資。
37.可否描寫1下甚么是關聯的和不關聯的子查詢?
在關聯的子查詢中,內層查詢依賴于外層查詢,對外層查詢的每行履行。非關聯的子查詢不依賴于外層查詢,可以獨立履行。因此,前者慢,后者快。順便說1下,關聯的子查詢有1些很棒的利用,其中包括在雇員表中查找第N
高的工資,這在上1道SQL
問題中也有提到。
38.正則表達式是甚么意思?
正則表達式是在文本型數據上進行模式匹配的方法。它是1種搜索的強有力方法,例如搜索長字符串中的某些字符,例如搜索1本書中是不是含有某個單詞。所有主流程序設計語言都支持正則表達式,但是Perl
正則表達式的能力是著名的。Java
的java.util.regex
包也支持類似Perl
的正則表達式。你可以用正則表達式檢查email
地址是不是有效,電話號碼是不是有效,郵政編碼是不是有效,乃至社會保險號(SSN
)是不是有效。正則表達式最簡答的例子之1是檢查字符串是否是1個數。
39.不用算術運算符,如何判定1個數是不是是2的冪?
當你聽到不能用算術運算符的限制時,應當立刻假定這是1道關于位運算的題。如果沒有這條限制,那末你可以輕松地用取模和除運算符檢查1個數是否是2的冪。用位運算符,有1個很奇妙的方法來完成任務。你可以用下面這段代碼來檢查1個數是否是2的冪
public static boolean powerOfTwo(int x) {
return (x & (x - 1)) == 0;
}
x & (x⑴)
是1個很棒的技能,可以將最右側的為1
的位設為0
。我是從《高效程序的奧秘》這本書中學到的。
40.如何在UNIX
上找到1個正在運行的Java
進程?
你可以組合使用ps
和grep
命令來查找UNIX
機器上的任何進程。假定你的Java
進程著名字,或有任何可以用來匹配的文字,那末使用這個命令。
ps -ef | grep “myJavaApp”
ps -e
將列出所有的進程(所有用戶的進程,不只是你的),ps -f
將顯示所有細節,包括PID
。如果你想要深入調查或用kill
命令殺死這個進程,你會需要PID
。
41.如何在UNIX
中尋覓大的文件,例如1GB
以上的文件?
你可以輕松地用find
命令尋覓大的文件,由于它提供根據大小尋覓文件的選項。如果你的文件系統滿了,你的Java
進程由于沒有空間而崩潰,那末就使用這個命令。這個命令可以列出所有大于1GB
的文件。你可以很容易地改變大小,例如尋覓所有100MB
以上的文件,就用+100M
。
find .
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈