前言
面試別人没隘,對(duì)我來(lái)說(shuō)是一件新奇事,以前都是別人面試我禁荸。
我清楚地知道右蒲,我在的地域與公司,難以吸引到中國(guó)的一流軟件人才屡限。所以品嚣,我特地調(diào)低了期望,很少問(wèn)什么深入的技術(shù)問(wèn)題钧大,只問(wèn)一些廣泛的翰撑、基礎(chǔ)的。我只要最終給Leader一句“這個(gè)人技術(shù)還行/很好/非常好”啊央,就行了眶诈。至于其它能力、綜合水平瓜饥,由別人把關(guān)逝撬。為此,在挑選唯一的一道筆試題時(shí)乓土,我特別地上心宪潮。
首先溯警,我不敢用網(wǎng)上那些廣為流傳的,比如Leetcode狡相、《程序員面試寶典》里的題——這些都太難了梯轻!正兒八經(jīng)做,其實(shí)很少有人能在1小時(shí)內(nèi)完美做出來(lái)尽棕,除非之前遇到過(guò)喳挑。我本人也并非什么思維敏捷的牛人,不然也不會(huì)混得這么慘滔悉。正所謂己所不欲伊诵,勿施于人,我也不希望以后別人考我特別麻煩的算法題回官,所以自創(chuàng)了一道特別簡(jiǎn)單的曹宴。
其次,對(duì)(Android平臺(tái)的)Java程序員來(lái)說(shuō)歉提,大多數(shù)情況下不需要寫(xiě)什么復(fù)雜的算法浙炼。相反,Java層主要做的是界面控制唯袄、業(yè)務(wù)邏輯、數(shù)據(jù)流之類(lèi)的蜗帜,更提倡代碼的簡(jiǎn)單和可讀恋拷,盡量用既有的公共類(lèi)庫(kù),不惜損失一些運(yùn)行效率厅缺。拿一道復(fù)雜的算法題蔬顾,考一個(gè)Java程序員,多少有點(diǎn)刁難人湘捎。
最后诀豁,還是那個(gè)薪資待遇和人才梯度問(wèn)題。沒(méi)有Google的工資窥妇,就別考Google的題舷胜;沒(méi)有Google的向心力,就別期待有Google級(jí)別的人才來(lái)面試活翩。
亮題
以下有一個(gè)static method烹骨,類(lèi)外會(huì)調(diào)用它,一個(gè)個(gè)地插入一些元素進(jìn)入一個(gè)List材泄【诨溃可以改變這個(gè)List內(nèi)容的,只有這一個(gè)method拉宗,要求任何時(shí)候這個(gè)List都是有序的峦树。
比如辣辫,依次插入3、2魁巩、1急灭、2,我希望List的順序是1歪赢、2化戳、2、3埋凯。
class Solution {
private static List<Integer> sSorted = new LinkedList<>();
public static void addElement(int e) {
// TODO: Insert e to sSorted and make sure sSorted is always sorted.
}
}
我會(huì)給出15分鐘的時(shí)間点楼,而其實(shí)往往會(huì)再多給10分鐘。(有興趣白对,你可以停在這試試掠廓。相信在看文章這種輕松的環(huán)境下,理清這道題的思路也就10~30秒甩恼。)
(為什么下限是10秒呢蟀瞧?唉……一不小心暴露了我智商的峰值。我實(shí)際問(wèn)過(guò)一些同事条摸,他們通常在理解的同時(shí)悦污,就立刻給出了正確的思路,過(guò)程不足5秒钉蒲,其中甚至包括一個(gè)硬件工程師切端,和一個(gè)只負(fù)責(zé)溝通和文檔的妹子。)
提示
在過(guò)程中顷啼,我會(huì)逐步給出一些提示踏枣,從接口到思路,都會(huì)主動(dòng)提供钙蒙,其它也基本有問(wèn)必答茵瀑。如果單純考算法,C語(yǔ)言才是最合適的躬厌,因?yàn)樗鼪](méi)有什么高級(jí)的工具類(lèi)马昨,什么復(fù)雜點(diǎn)的都得自己寫(xiě)。而Java扛施,則有一些“基礎(chǔ)”類(lèi)庫(kù)是難以記憶的偏陪。比如前面出現(xiàn)的java.util.List,就沒(méi)有多少人能在紙上寫(xiě)出它的常用接口煮嫌。
我并不想考察什么死記硬背笛谦,在這個(gè)時(shí)代,斷網(wǎng)后本來(lái)就沒(méi)幾個(gè)程序員能正常編程昌阿。所以我會(huì)主動(dòng)提供一份List的不完全接口列表饥脑。
public interface List<E> extends Collection<E> {
public void add(int location, E object);
public void add(E object);
public void clear();
public boolean contains(Object object);
public boolean equals(Object object);
public E get(int location);
public int indexOf(Object object);
public boolean isEmpty();
public E remove(int location);
public E set(int location, E object);
public int size();
}
我沒(méi)有給出完全的接口恳邀,因?yàn)榻o多了無(wú)疑是誤導(dǎo)人。真正能用上的接口其實(shí)也就3個(gè)灶轰,但我也總不能只給3個(gè)谣沸,提示得太明顯,也限制了對(duì)方的思路笋颤。所以乳附,給出了可能用得上的這幾個(gè)。我也沒(méi)給出注釋?zhuān)驗(yàn)橛新暶骶鸵呀?jīng)夠了伴澄。而且如果對(duì)方問(wèn)起赋除,我也會(huì)給出解釋。
一開(kāi)始我想非凌,考一個(gè)排序算了举农。但是轉(zhuǎn)念一想,這也太不負(fù)責(zé)任了敞嗡。對(duì)面要是背一道冒泡排序的解法上來(lái)颁糟,達(dá)不到考察技術(shù)水平的目的,Boss也不會(huì)認(rèn)可喉悴。本著“放水不能太明顯”的原則棱貌,我想考插入排序,并且把題目弄得沒(méi)多少人見(jiàn)過(guò)箕肃。
排序是一類(lèi)基本算法键畴,合格的程序員至少會(huì)一種。大多數(shù)人都只會(huì)入門(mén)級(jí)的冒泡排序突雪,而我更喜歡插入排序,原因……你會(huì)明白的涡贱。
插入排序咏删,其實(shí)就是把數(shù)組或列表在邏輯上分成兩部分,一部分是待排序的问词,一部分是有序的督函。一開(kāi)始,有序的部分只有一個(gè)元素(或者一個(gè)都沒(méi)有)激挪,然后從待排序的部分里一個(gè)個(gè)抽出來(lái)辰狡,插入到有序的部分。等元素都插入到了有序的部分垄分,排序過(guò)程也就完成了宛篇。
你看,也就抽插N次的事薄湿。而我這道題叫倍,就是只考插入排序算法的一半偷卧,會(huì)插就行。
在面試過(guò)程中吆倦,我甚至常常親自解釋插入排序是怎么回事——放水到這個(gè)份上听诸,我都不忍心再退步了。
真正的考察點(diǎn)
這是一份Android平臺(tái)的開(kāi)發(fā)工作蚕泽,Boss要求的是能干活晌梨、干好活。我給出的建議要求是:
- 熟悉Java须妻。
- 有良好的溝通仔蝌、表達(dá)能力。
- 學(xué)習(xí)能力強(qiáng)璧南,喜歡不斷拓展計(jì)算機(jī)領(lǐng)域的知識(shí)掌逛。
- 有良好的編碼習(xí)慣,愿意為代碼的簡(jiǎn)潔司倚、優(yōu)雅而反復(fù)修改豆混。
我建議Boss放棄學(xué)歷和工作年限的要求,技術(shù)崗位就應(yīng)該只考察技術(shù)(和其它基本能力)动知,不應(yīng)該考察技術(shù)的間接證明皿伺。
Java是Android的基本功(我們不玩Kotlin、Scala盒粮、React Native等新花樣)鸵鸥,這門(mén)語(yǔ)言如果不扎實(shí),那至少得帶半年丹皱。
我沒(méi)有在Android崗明確地要求考察Android妒穴,是因?yàn)锳ndroid的那些東西相對(duì)來(lái)說(shuō)容易學(xué)習(xí)。即便是毫無(wú)經(jīng)驗(yàn)的新手摊崭,要搞清楚什么“四大組件”“五大布局”讼油,也就一兩天的事。而如果Java不夠扎實(shí)呢簸,各種肉眼可見(jiàn)的大小bug就會(huì)層出不窮矮台,知識(shí)盲點(diǎn)一兩年都補(bǔ)不完。
溝通是職場(chǎng)基本功根时。如果話都說(shuō)不清瘦赫,那么會(huì)顯著降低團(tuán)隊(duì)的溝通效率。而且蛤迎,我個(gè)人認(rèn)為确虱,話說(shuō)不清的人,代碼一定寫(xiě)不好替裆。語(yǔ)言條理清晰蝉娜,邏輯層次分明唱较,體現(xiàn)到代碼上,就是簡(jiǎn)潔召川、明朗南缓。
學(xué)習(xí)能力、求知欲荧呐,是作為一個(gè)程序員的基本素養(yǎng)汉形。因?yàn)椋蟛糠秩说墓ぷ鞅恫?lèi)似于在一堆按鈕中概疆,找到合適的那個(gè)按下去;而程序員的工作峰搪,往往是閉著眼睛這么干岔冀。開(kāi)發(fā)工程師通常是在一堆未知(沒(méi)讀過(guò)的代碼、不知道的接口)中概耻,把一小部分變成已知(讀懂了的代碼或接口)使套,進(jìn)行一些增刪改,最后達(dá)成外界(產(chǎn)品經(jīng)理、設(shè)計(jì)師、測(cè)試工程師)賦予的業(yè)務(wù)目標(biāo)也颤。
一些職業(yè)賣(mài)口水,一些職業(yè)賣(mài)口才县好。一些職業(yè)賣(mài)青春,一些職業(yè)賣(mài)肉體(咳咳,我說(shuō)的是空姐和搬磚,想歪的去面壁)瞧壮。一些職業(yè)賣(mài)知識(shí),一些職業(yè)賣(mài)能力匙握。
程序員咆槽,或者說(shuō)軟件開(kāi)發(fā)工程師,賣(mài)的是學(xué)習(xí)能力(其實(shí)也包括青春和肉體)肺孤,快速學(xué)會(huì)各種知識(shí),找到那些藏在屏幕外的按鈕济欢,并且正確的按下去赠堵。比如,像Bash這類(lèi)Command line工具法褥,就是自己敲命令出來(lái)執(zhí)行茫叭,而不是去界面上找功能對(duì)應(yīng)的按鈕;而程序設(shè)計(jì)半等、實(shí)現(xiàn)揍愁,就是去發(fā)現(xiàn)呐萨、或者創(chuàng)造一種解決問(wèn)題的辦法,然后用代碼表達(dá)出來(lái)——你看莽囤,都是在干一些反UI谬擦、UX設(shè)計(jì)的事。唯有不斷地學(xué)習(xí)朽缎,才能提高效率惨远,把自己從加班中解脫出來(lái),把項(xiàng)目從bug中拯救出來(lái)话肖。所以北秽,厭學(xué)的人當(dāng)不了好程序員,也干不長(zhǎng)最筒。
編碼習(xí)慣贺氓,相對(duì)次之。部分觀點(diǎn)認(rèn)為床蜘,這東西伴隨一生辙培,如果一開(kāi)始沒(méi)有好習(xí)慣,這輩子都沒(méi)辦法改了悄泥。Boss就是這么認(rèn)為的虏冻,我倒是不這么認(rèn)為。我相信編碼習(xí)慣的可塑性是很高的——你不按規(guī)范寫(xiě)弹囚,我不給你merge厨相,改不改?
但是鸥鹉,編碼習(xí)慣作為程序員的軟技能蛮穿,還是可以一定程度上看出其技術(shù)素養(yǎng)、代碼質(zhì)量的毁渗。至于優(yōu)雅什么的践磅,我其實(shí)沒(méi)有真的敢這么期待。
所以灸异,我這道題其實(shí)是考察這四點(diǎn)府适。
- 能寫(xiě)出來(lái),并且無(wú)明顯問(wèn)題肺樟,代表Java基本功扎實(shí)檐春。
- 理解我對(duì)題目的描述,和我確認(rèn)清楚題目的細(xì)節(jié)么伯,這是看溝通能力疟暖。
- List接口不知道,我給你啊俐巴;插入排序不會(huì)骨望,我教你啊欣舵;其它還有什么不會(huì)擎鸠,你問(wèn)啊——這是在考察學(xué)習(xí)能力。
- 代碼的字里行間邻遏,可以明顯看出編碼習(xí)慣糠亩。
面試結(jié)果
總體來(lái)說(shuō),我很傷心准验。
第一位就讓我很傷心赎线,當(dāng)我看了他前兩行代碼,就不忍心接著往下看:
private static List<Integer> sSorted = new LinkedList<>();
public static void addElement(int e) {
if (null == sorted) {
sorted.add(e);
}
// I couldn't read more!
第一行就編譯不過(guò)糊饱。如果他對(duì)Java的一些命名規(guī)范有一定的了解垂寥,就絕不會(huì)把sSorted寫(xiě)成sorted。(當(dāng)然另锋,sSorted也許并不是合適的命名方式滞项,因?yàn)閟和m這類(lèi)前綴有些冗余。我通常遵守Android源碼的通用規(guī)范夭坪,它是有這類(lèi)前綴的文判。)
第二行必然拋出NullPointerException,而不知道是該慶幸還是悲傷的是室梅,它永遠(yuǎn)執(zhí)行不到戏仓。根據(jù)我已經(jīng)給出的一個(gè)接口addElement,和可以猜到或者問(wèn)出來(lái)的讀取接口亡鼠,都是不會(huì)把sSorted變成null的赏殃。這體現(xiàn)了溝通、理解能力的一點(diǎn)問(wèn)題间涵。
此外仁热,即使sSorted因?yàn)槭裁碽ug而變成null,這里也不應(yīng)該做處理勾哩,而是任其拋出NullPointerException抗蠢,或者轉(zhuǎn)義一下,主動(dòng)拋出IllegalStateException思劳。否則迅矛,此處將變成一個(gè)不會(huì)crash的隱藏bug。不能用正常處理敢艰,代替異常處理诬乞;當(dāng)然册赛,也不能用異常處理钠导,代替流程控制震嫉。
另外,更令我失望的是牡属,有一位是這么寫(xiě)的:
for (int i = 0; i < sSorted.size(); i++) {
if (e == sSorted.get(i)) {
sSorted.add(i, e);
}
}
我問(wèn)他票堵,如果這個(gè)元素不在這個(gè)List里存在怎么辦?如果這個(gè)List是空的怎么辦逮栅?他頓時(shí)一囧悴势,我也一起囧,心想自己是不是太壞了措伐。
還有一位特纤,仿佛聽(tīng)見(jiàn)了我這幾個(gè)問(wèn)題,他竟然一一作答:
if (sSorted.size == 0) {
sSorted.add(e);
return;
}
if (e >= sSorted.get(sSorted.size - 1)) {
sSorted.add(e);
return;
}
if (e <= sSorted.get(0)) {
sSorted.add(0, e);
return;
}
if (sSorted.contains(e)) {
sSorted.add(sSorted.indexOf(e), e);
return;
}
// more...
他想干什么呢侥加?也許是優(yōu)化性能吧捧存,只能這么幫腔了。另外担败,他對(duì)size的理解昔穴,和數(shù)組的length相同。
這位算是經(jīng)驗(yàn)比較豐富(30歲)提前,對(duì)Java的理解比較深入的了吗货。他說(shuō)排序不需要手寫(xiě),Java里有現(xiàn)成的接口狈网。我說(shuō)宙搬,是這樣沒(méi)錯(cuò),但接口我沒(méi)給出孙援,如果你記得害淤,那就寫(xiě)出來(lái)吧。
于是他在剛才那一大段“優(yōu)化”的后面拓售,這么寫(xiě)了:
sSorted.add(e);
sSorted.sort(new Comp...able() {
public boolean ?(left, right) {
return right >= left;
}
});
思路上窥摄,插入后再排序,我先不吐槽础淤。我明明說(shuō)了“記得”再寫(xiě)崭放,這Comparable及其接口int compareTo(T another)如果記不清,我就當(dāng)看lambda表達(dá)式了鸽凶”疑埃可是,他這個(gè)?分明是Comparator的int compare(T lhs, T rhs)接口呀玻侥!
不過(guò)决摧,其實(shí)這些我都可以捏著鼻子認(rèn)了,因?yàn)槲乙彩謱?xiě)不出來(lái)。但List是沒(méi)有sort方法的呀掌桩!
Arrays和Collections才有各自的sort方法边锁,它倆算是銀彈型工具類(lèi),而Array和Collection是沒(méi)有的波岛。這個(gè)細(xì)節(jié)茅坛,誰(shuí)用誰(shuí)知道,知道了就絕不會(huì)記錯(cuò)则拷,盡管就差一個(gè)s贡蓖。
還有一位,他先插入煌茬、再冒泡排序斥铺,是這么寫(xiě)的:
sSorted.add(e);
for (int i = 0, sSorted.size(i) > sSorted.get(e), i++) {
temp = sSorted.get(e);
sSorted.get(e) = sSorted.size(i);
sSorted.size(i) = temp;
}
- 你沒(méi)看錯(cuò),for()里面是,分隔的坛善。
- 你沒(méi)看錯(cuò)仅父,temp是從石頭縫里蹦出來(lái)的。
- 你沒(méi)看錯(cuò)浑吟,List.get(e)是可以對(duì)其賦值的笙纤。
- 你沒(méi)看錯(cuò),List.size(i)是可以傳參數(shù)進(jìn)去的组力。
還有兩位省容,直接交白卷放棄了。
其中一位還比較認(rèn)真燎字,思考了一會(huì)兒腥椒,說(shuō)“我不想浪費(fèi)時(shí)間”。
我沒(méi)亂用詞候衍,他確實(shí)“比較認(rèn)真”笼蛛。另一位在我遞過(guò)去后,直接看兩眼就遞回來(lái)蛉鹿,“排序我不會(huì)”滨砍,然后看手機(jī)去了。
參考答案
我自己在紙上寫(xiě)的時(shí)候妖异,花了大概5分鐘去思考細(xì)節(jié)惋戏,再花5分鐘寫(xiě)出來(lái)。(唉……一不小心他膳,又暴露了自己奇慢無(wú)比的思維响逢,以及奇慢無(wú)比的寫(xiě)字速度。)這比我此前預(yù)計(jì)的時(shí)間多了好幾倍棕孙!
不過(guò)舔亭,以我給的15~25分鐘些膨,應(yīng)該不算太難為人……吧?
class Solution {
private static List<Integer> sSorted = new LinkedList<>();
public static void addElement(int e) {
int i;
for (i = 0; i < sSorted.size(); ++i) {
if (e <= sSorted.get(i)) {
break;
}
}
sSorted.add(i, e);
}
}
這是我自己在紙上寫(xiě)的答案钦铺。(如果有興趣傀蓉,可以停在此處,考慮下這是否是最優(yōu)算法职抡。)
@Override
public E get(int location) {
if (location >= 0 && location < size) {
Link<E> link = voidLink;
if (location < (size / 2)) {
for (int i = 0; i <= location; i++) {
link = link.next;
}
} else {
for (int i = size; i > location; i--) {
link = link.previous;
}
}
return link.data;
}
throw new IndexOutOfBoundsException();
}
這是 java.util.LinkedList在Android(API 23)上的實(shí)現(xiàn),而反編譯Oracle JDK 1.8的實(shí)現(xiàn)也大同小異误甚。也就是說(shuō)缚甩,我寫(xiě)的答案雖然看似簡(jiǎn)潔,但其最壞時(shí)間復(fù)雜度與先插入再排序也沒(méi)太大區(qū)別窑邦,都是O(n2)擅威。
終日打燕,反而被燕啄了眼8郧铡(暴露了真實(shí)水平郊丛。)
我后來(lái)又寫(xiě)了一個(gè)參考答案,算是勉強(qiáng)在臉上摸了些防曬霜瞧筛。(大家有興趣可以想想為什么這是一個(gè)改進(jìn)厉熟。當(dāng)然,一定還有更好的方案较幌。)
class Solution {
private static List<Integer> sSorted = new LinkedList<>();
public static void addElement(int e) {
int i = 0;
for (int j : sSorted) {
if (e <= j) {
break;
}
++i;
}
sSorted.add(i, e);
}
}
(我沒(méi)有在提示列表中給出迭代器揍瑟,結(jié)果自己也被晃過(guò)去了。)
隱藏的殺手锏
面試官在出題考察應(yīng)聘者時(shí)乍炉,應(yīng)聘者也在通過(guò)這道題考察這家公司绢片。
為了避免讓人覺(jué)得這家公司考題太簡(jiǎn)單、工作內(nèi)容太無(wú)趣岛琼、里面的員工(我)水平太低底循,我還準(zhǔn)備了一些后續(xù)問(wèn)題,由淺入深槐瑞,作為殺手锏熙涤。
- 為什么LinkedList可以賦值給List?
考察多態(tài)(polymorphism)困檩。- 為什么List<Integer>要寫(xiě)<>內(nèi)的內(nèi)容灭袁,而LinkedList<>()可以不寫(xiě)?
考察泛型(generic)窗看。- 為什么List里面是Integer茸歧,但放進(jìn)去和拿出來(lái)的都是int?
(此處有坑显沈,其實(shí)拿出來(lái)的還是Integer软瞎。)
考察基本數(shù)據(jù)類(lèi)型的自動(dòng)裝箱逢唤、拆箱(auto boxing/unboxing)。- 如何在外面有多線程調(diào)用時(shí)涤浇,保證這個(gè)唯一的List的正確性鳖藕?
考察synchronized和volatile。- 如何在多線程狀態(tài)下的每一個(gè)線程只锭,各保持一個(gè)獨(dú)立的List著恩?
考察ThreadLocal。
(當(dāng)然蜻展,還有一些和Android相關(guān)的問(wèn)題喉誊。)
我真心是沒(méi)想考算法,所以連算法復(fù)雜度的評(píng)估都沒(méi)打算問(wèn)纵顾。實(shí)際情況是伍茄,我往往沒(méi)有機(jī)會(huì)問(wèn)這些問(wèn)題,因?yàn)闆](méi)幾個(gè)人寫(xiě)出來(lái)施逾。
吐槽與建議
首先敷矫,噴一下大學(xué)擴(kuò)招……算了,不扯這么遠(yuǎn)了汉额。那兩位放棄做題的曹仗,一個(gè)是計(jì)算機(jī)學(xué)院的,一個(gè)是軟件工程學(xué)院的蠕搜。排序?qū)懖怀鰜?lái)整葡,竟然也是能畢業(yè)的!
有兩位是某App的開(kāi)發(fā)者讥脐。我把他們的App下載下來(lái)遭居,發(fā)現(xiàn)了一堆bug后,本來(lái)想忍忍旬渠、就當(dāng)沒(méi)看見(jiàn)俱萍、碼農(nóng)何苦為難碼農(nóng),然后手機(jī)發(fā)熱告丢、卡頓枪蘑、滅屏后幾乎點(diǎn)亮不了(內(nèi)存泄露吃光了RAM,導(dǎo)致系統(tǒng)進(jìn)程沒(méi)有內(nèi)存可用)岖免。過(guò)了一陣最終好了岳颇,我查看耗電排行,運(yùn)行10分鐘就高居榜首颅湘,耗了17%的電——我嚇得立刻卸載了话侧。一個(gè)第三方App能把系統(tǒng)給卡成這樣,一般人還真做不到闯参。
還有兩位是“相關(guān)專(zhuān)業(yè)”的瞻鹏,非計(jì)算機(jī)悲立、軟件工程專(zhuān)業(yè),反而表現(xiàn)最佳新博,雖然還是沒(méi)寫(xiě)出來(lái)薪夕。
他們無(wú)一例外,都是在大學(xué)以外赫悄,又參加過(guò)某些Java原献、Android培訓(xùn)的。這些培訓(xùn)班的水平埂淮,可見(jiàn)一斑姑隅。問(wèn)題倒不一定是培訓(xùn)班的教學(xué)質(zhì)量,而是這種大規(guī)模提供人才轉(zhuǎn)型服務(wù)的形式本身——這個(gè)世界上同诫,本來(lái)就不是誰(shuí),都能當(dāng)一個(gè)好碼農(nóng)樟澜,哪怕工作要求只是復(fù)制粘貼误窖。
現(xiàn)在,很多碼農(nóng)都戲稱(chēng)自己是在“搬磚”秩贰、復(fù)制粘貼霹俺,但實(shí)際上程序員的工作不可能僅止于此。使用別人寫(xiě)好的基本算法毒费,參考別人的實(shí)現(xiàn)代碼丙唧,只是為了集中精力去解決抽象層次更高的業(yè)務(wù)問(wèn)題。
“我們不寫(xiě)代碼觅玻,我們只做代碼的搬運(yùn)工想际。”——萬(wàn)萬(wàn)不可把這句話當(dāng)做信條溪厘。
還有很多人胡本,在沒(méi)有Demo的情況下,無(wú)論給多么詳細(xì)的API或其它資料畸悬,仍然無(wú)法寫(xiě)代碼侧甫。他們只能在既有的基礎(chǔ)上,修修補(bǔ)補(bǔ)蹋宦,無(wú)法憑空創(chuàng)作披粟。
我推薦三本Java的基礎(chǔ)書(shū):
《Java編程思想》(Think in Java)
這本是最合適的Java語(yǔ)言入門(mén)書(shū)。其它很多語(yǔ)法書(shū)都是從C/C++的角度來(lái)講Java的變化冷冗,或者從C++的思路來(lái)討論Java怎么用守屉,而這本書(shū)的英文名則直接告訴你,請(qǐng)用Java來(lái)思考蒿辙、解決問(wèn)題胸梆。《Effective Java》
Java中有很多坑敦捧,Java中也有很多糖。如果沒(méi)有看過(guò)這本書(shū)碰镜,那么不知不覺(jué)就會(huì)犯很多大忌兢卵。《代碼整潔之道》(Clean Code)
我是在獨(dú)立寫(xiě)一個(gè)小項(xiàng)目的時(shí)候開(kāi)始看的⌒饔保看到一半時(shí)項(xiàng)目也寫(xiě)到一半秽荤,頓時(shí)連代碼都不會(huì)寫(xiě)了!每天都在寫(xiě)自己看不下去的代碼柠横,而不知道怎么寫(xiě)能看得過(guò)眼的窃款。加速看完后,重新開(kāi)始會(huì)寫(xiě)代碼牍氛。最終晨继,項(xiàng)目后半部分的代碼,和前半部分完全不同搬俊,不像一個(gè)人寫(xiě)的紊扬,我后來(lái)又重構(gòu)了一遍。
(為什么我不多推薦點(diǎn)書(shū)呢唉擂?一來(lái)餐屎,是我本人也沒(méi)看過(guò)多少,囧玩祟;二來(lái)腹缩,三本是極限,根據(jù)我的經(jīng)驗(yàn)空扎,推薦三本可以讓人看一本藏鹊,推薦三本以上,受眾一本也不會(huì)看转锈。)
我有一個(gè)朋友伙判,也是一個(gè)前同事,好學(xué)如好色黑忱。他周末都在找一個(gè)大學(xué)教室看書(shū)宴抚,甚至有時(shí)請(qǐng)年假去教室看書(shū)。一本《Java編程思想》甫煞,逐行精讀三遍以上菇曲。工作經(jīng)驗(yàn)不足兩年,跳槽三次抚吠,現(xiàn)在在一家百億級(jí)上市公司常潮,年薪三十萬(wàn),統(tǒng)率十人楷力。
究其原因喊式,無(wú)非基礎(chǔ)知識(shí)扎實(shí)孵户,口水噴死面試官爾
后記
我作為一個(gè)面試別人的初哥,一心只想著自己喜歡的抽插……呃不岔留,插入排序算法夏哭,給別人造成了不必要的麻煩,只能說(shuō)抱歉了献联。
和我一起面試的竖配,還有一個(gè)負(fù)責(zé)文檔和規(guī)范的妹子(前面提到過(guò)的那個(gè))。她也是有一票否決權(quán)的里逆,而且用得比我更頻繁进胯!
我最多只給交白卷的,和那個(gè)耗電超恐怖的App原押,這幾個(gè)人直接否決胁镐。而這個(gè)妹子,考察對(duì)方的其它綜合能力诸衔。
在實(shí)際工作中盯漂,她是需求的接口人,我們需要和她溝通署隘,實(shí)現(xiàn)各方對(duì)我們團(tuán)隊(duì)的需求宠能。所以亚隙,只要她說(shuō)一句“我和這個(gè)人難以溝通”磁餐,那么Boss基本上就直接拒絕了。
下次我還是換一道更簡(jiǎn)單的吧阿弃,碼農(nóng)何苦為難碼農(nóng)诊霹。