"我是培訓+外包出來的,確實有被甲方嫌棄過",開發八年後面試字節Android資深工程師定薪60W成功逆襲!

關於培訓出身的程序員

圈子裏,科班程序員“鄙視”培訓機構程序員似乎已經隱隱成了一種共識。

“培訓機構出來的程序員幾乎什麼也不會。不用看技術,剛剛培訓出來的就是假大空。”網上甚至有更偏激的觀點:培訓班出來的全是垃圾,沒有例外。

“培訓機構出來的程序員基礎薄弱很多,對某項語言可能有點熟悉但是很死板,代碼環境一變可能就不會了,更差點的就直接被當成‘敲代碼機器’了。很多人剛出來沒有完整的案例操作,對這個行業還沒有基礎的認知,更別提思維、格局了。

外界的這些言論無形中成爲這些程序員心中的刺。很多培訓機構出來的程序員在面試時是不會告訴用人單位培訓背景的,有些人甚至會刻意隱瞞這段經歷。“好多人被公司知道後就直接被辭退了,有的人還揹着房貸、要贍養老人,但也沒有辦法。”

在很多人看來,培訓機構其實是複製粘貼出來一堆差不多的人。“人家用大學四年打下基礎,你培訓幾個月速成,很難完全領悟。”

但是科班程序員對這個問題感受好像並沒有那麼強烈,碩士畢業直接進入互聯網公司工作的一位程序員說:“員工間談不上鄙視,主要是看他們做的工作是不是好,但是一般情況下,培訓班出來的工作質量不會太好。代碼混亂、質量低、bug 多、沒法維護,別人接手你的代碼會很難受。

“大家都是打工的,沒有人會管你是哪裏出來的。我們只會鄙視那些技術垃圾的、配合不了的。至於你是哪裏出來的,並不會很在意。”補充道。

對於這個問題,某互聯網公司技術總監曾經說過:外界的確存在一些公司認爲培訓班出來的程序員是“速成品”,然後卡簡歷的情況。“其實不是說培訓機構出來的程序員表現都不行,只是表現不好的程序員可能都有過培訓經歷,行業裏一傳十、十傳百就會認爲培訓機構出來的程序員都不行。”

培訓 + 外包拿下字節歷程

我認識的一位培訓+外包出身的程序員,目前開發8年多,最近去面試了今日頭條的移動Android資深工程師,定薪年薪60W!果然功夫還是不負有心人啊,只要堅持努力總會有結果的!

接下來分享一下他的Android資深工程師面試經歷:

今日頭條的面試主要分爲三輪,首先是基礎面試,基本面試10個題左右。

第一面是北京的開發進行視頻面試,有理論和編程題組成。用的是在線編程工具,如下圖;

第一面

1,請編程實現單例模式,懶漢和飽漢寫法

//飽漢寫法
public static Singleton getInstance() {  
        if (singleton == null) {    
            synchronized (Singleton.class) {    
               if (singleton == null) {    
                  singleton = new Singleton();   
               }    
            }    
        }    
        return singleton;   
    }

   //懶漢寫法
    private static final Singleton1 single = new Singleton1();  
    //靜態工廠方法   
    public static Singleton1 getInstance() {  
        return single;  
    } 

2,請編程實現Java的生產者-消費者模型

看到這個有點懵逼,要是大學畢業的時候寫這個肯定沒問題,這都工作多年,這也只能按照自己的思路寫了。我使用synchronized鎖以及wait notify實現一個比較簡單的。這裏就不作展示了

3,HashMap的內部結構? 內部原理?

關於HashMap的問題,不再詳述,這方面的資料也挺多,不過需要注意的是Java1.7和1.8版本HashMap內部結構的區別。

4,請簡述Android事件傳遞機制, ACTION_CANCEL事件何時觸發?

第一個問題不做解釋。。

關於ACTION_CANCEL何時被觸發,系統文檔有這麼一種使用場景:

在設計設置頁面的滑動開關時,如果不監聽ACTION_CANCEL,在滑動到中間時,如果你手指上下移動,就是移動到開關控件之外,則此時會觸發ACTION_CANCEL,而不是ACTION_UP,造成開關的按鈕停頓在中間位置。
意思是當滑動的時候就會觸發,不知道大家搞沒搞過微信的長按錄音,有一種狀態是“鬆開手指,取消發送”,這時候就會觸發ACTION_CANCEL。>

5,Android的進程間通信,Liunx操作系統的進程間通信。
關於這個問題也是被問的很多,不多囉嗦瞭解釋了。

6,JVM虛擬機內存結構,以及它們的作用。
這個問題也比較基礎,JVM的內存結構如下圖所示。

7,簡述Android的View繪製流程,Android的wrap_content是如何計算的。

8,有一個整形數組,包含正數和負數,然後要求把數組內的所有負數移至正數的左邊,且保證相對位置不變,要求時間複雜度爲O(n), 空間複雜度爲O(1)。例如,{10, -2, 5, 8, -4, 2, -3, 7, 12, -88, -23, 35}變化後是{-2, -4,-3, -88, -23,5, 8 ,10, 2, 7, 12, 35}。

要實現上面的效果有兩種方式:

第一種:兩個變量,一個用來記錄當前的遍歷點,一個用來記錄最左邊的負數在數組中的索引值。然後遍歷整個數組,遇到負數將其與負數後面的數進行交換,遍歷結束,即可實現負數在左,正數在右。

第二種:兩個變量記錄左右節點,兩邊分別開始遍歷。左邊的節點遇到負值繼續前進,遇到正值停止。右邊的節點正好相反。然後將左右節點的只進行交換,然後再開始遍歷直至左右節點相遇。這種方式的時間複雜度是O(n).空間複雜度爲O(1)

//方法1
 public void setParted(int[] a){  
        int temp=0;  
        int border=-1;  

        for(int i=0;i<a.length;i++){  
            if(a[i]<0){  
                temp=a[i];  
                a[i]=a[border+1];  
                a[border+1]=temp;  
                border++;  
            }  
        }  
        for(int j=0;j<a.length;j++){  
            System.out.println(a[j]);  
        }  
    }  

//方法2
public void setParted1(int[] a,int left,int right){  
        if(left>=right||left==a.length||right==0){  
            for(int i=0;i<a.length;i++){  
                System.out.println(a[i]);  
            }  
            return ;  
        }  
        while(a[left]<0){  
            left++;  
        }  
        while(a[right]>=0){  
            right--;  
        }  
        if(left>=right||left==a.length||right==0){  
            for(int i=0;i<a.length;i++){  
                System.out.println(a[i]);  
            }  
            return;  
        }  
        swap(a,left,right);  
        left++;  
        right--;  
        setParted1(a,left,right);  
    }  
     private void swap(int a[],int left,int right){  
        int temp=0;  
        temp=a[left];  
        a[left]=a[right];  
        a[right]=temp;  
    }  
    public static void main(String[] args) {  
        int a[]={1,2,-1,-5,-6,7,-7,-10};  
        new PartTest().setParted1(a,0,a.length-1);   
    }  

顯然,第二種實現的難點比較高,不過只要此種滿足條件。

第二面

1,bundle的數據結構,如何存儲,既然有了Intent.putExtra,爲啥還要用bundle。

bundle的內部結構其實是Map,傳遞的數據可以是boolean、byte、int、long、float、double、string等基本類型或它們對應的數組,也可以是對象或對象數組。當Bundle傳遞的是對象或對象數組時,必須實現Serializable 或Parcelable接口。

2,android的IPC通信方式,是否使用過

這方面的資料比較多,也不方便闡述

3,Android的多點觸控如何傳遞 核心類
4,asynctask的原理 AsyncTask是對Thread和Handler的組合包裝。
5,android 圖片加載框架有哪些,對比下區別
6,圖片框架的一些原理知識
7,其他的一些Android的模塊化開發,熱更新,組件化等知識。

三面;主流框架

在Android面試的時候,經常會被問到一些Android開發中用到的一些開發框架,如常見的網絡請求框架Retrofit/OkHttp,組件通信框架EventBus/Dagger2,異步編程RxJava/RxAndroid等。結合本次面試,整理下上面的幾個框架,大家可以拿去,面試備用

1. EventBus

EventBus是一個Android發佈/訂閱事件總線,簡化了組件間的通信,讓代碼更加簡介,但是如果濫用EventBus,也會讓代碼變得更加輔助。

面試EventBus的時候一般會談到如下幾點

(1)EventBus是通過註解+反射來進行方法的獲取的

(2)使用ConcurrentHashMap來保存映射關係 調用實體的構建:調用實體中對於Object,也就是實際執行方法的對象不應該使用強引用而是應該使用弱引用,因爲Map的static的,生命週期有可能長於被調用的對象,如果使用強引用就會出現內存泄漏的問題。

(3)方法的執行 使用Dispatcher進行方法的分派,異步則使用線程池來處理,同步就直接執行,而UI線程則使用MainLooper創建一個Handler,投遞到主線程中去執行。

2.Retrofit

要明確EventBus中最核心的,就是動態代理技術。

Java中的動態代理:

首先動態代理是區別於靜態代理的,代理模式中需要代理類和實際執行類同時實現一個相同的接口,並且在每個接口定義的方法前後都要加入相同的代碼,這樣有可能很多方法代理類都需要重複。而動態代理就是將這個步驟放入運行時的過程,一個代理類只需要實現InvocationHandler接口中的invoke方法,當需要動態代理時只需要根據接口和一個實現了InvocationHandler的代理對象A生成一個最終的自動生成的代理對象A。這樣最終的代理對象A無論調用什麼方法,都會執行InvocationHandler的代理對象A的invoke函數,你就可以在這個invoke函數中實現真正的代理邏輯。

Retrofit中的動態代理

Retrofit中使用了動態代理是不錯,但是並不是爲了真正的代理才使用的,它只是爲了動態代理一個非常重要的功能,就是“攔截”功能。我們知道動態代理中自動生成的A對象的所有方法執行都會調用實際代理類A中的invoke方法,再由我們在invoke中實現真正代理的邏輯,實際上也就是A的所有方法都被A對象給攔截了。 而Retrofit的功能就是將代理變成像方法調用那麼簡單。

Retrofit作用

Retrofit實際上是爲了更方便的使用Okhttp,因爲Okhttp的使用就是構建一個Call,而構建Call的大部分過程都是相似的,而Retrofit正是利用了代理機制帶我們動態的創建Call,而Call的創建信息就來自於你的註解。

3.OkHttp

請求任務隊列

Okhttp使用了一個線程池來進行異步網絡任務的真正執行,而對於任務的管理採用了任務隊列的模型來對任務執行進行相應的管理,有點類似服務器的反向代理模型。Okhttp使用分發器Dispatcher來維護一個正在運行任務隊列和一個等待隊列。如果當前併發任務數量小於64,就放入執行隊列中並且放入線程池中執行。而如果當前併發數量大於64就放入等待隊列中,在每次有任務執行完成之後就在finally塊中調用分發器的finish函數,在等待隊列中查看是否有空餘任務,如果有就進行入隊執行。Okhttp就是使用任務隊列的模型來進行任務的執行和調度的。

複用連接池

Http使用的TCP連接有長連接和短連接之分,對於訪問某個服務器的頻繁通信,使用短連接勢必會造成在建立連接上大量的時間消耗;而長連接的長時間無用保持又會造成資源你的浪費。Okhttp底層是採用Socket建立流連接,而連接如果不手動close掉,就會造成內存泄漏,那我們使用Okhttp時也沒有做close操作,其實是Okhttp自己來進行連接池的維護的。在Okhttp中,它使用類似引用計數的方式來進行連接的管理,這裏的計數對象是StreamAllocation,它被反覆執行aquire與release操作,這兩個函數其實是在改變Connection中的List<WeakReference<StreamAllocation>>大小。List中Allocation的數量也就是物理socket被引用的計數(Refference Count),如果計數爲0的話,說明此連接沒有被使用,是空閒的,需要通過淘汰算法實現回收。

4. RxJava

從15年開始,前端掀起了一股異步編程的熱潮,在移動Android編程過程中,經常會聽到觀察者與被觀察者等概念。

觀察者與被觀察者通信

Observable的通過create函數創建一個觀察者對象。

public final static <T> Observable<T> create(OnSubscribe<T> f) {
  return new Observable<T>(hook.onCreate(f));
}

Observable的構造函數如下:

protected Observable(OnSubscribe<T> f) {
  this.onSubscribe = f;
}

創建了一個Observable我們記爲Observable1,保存了傳入的OnSubscribe對象爲onSubscribe,這個很重要,後面會說到。

onSubscribe方法

public final Subscription subscribe(Subscriber<? super T> subscriber) {
  return Observable.subscribe(subscriber, this);
}
private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
  ...
  subscriber.onStart();
  onSubscribe.call(subscriber);
  return hook.onSubscribeReturn(subscriber);
}

線程切換過程(Scheduler)

RxJava最好用的特點就是提供了方便的線程切換,但它的原理歸根結底還是lift,使用subscribeOn()的原理就是創建一個新的Observable,把它的call過程開始的執行投遞到需要的線程中;而 observeOn() 則是把線程切換的邏輯放在自己創建的Subscriber中來執行。把對於最終的Subscriber1的執行過程投遞到需要的線程中來進行。

Android進階之路

對我們開發者來說,一定要打好基礎,隨時準備戰鬥。不論寒冬是否到來,都要把自己的技術做精做深。雖然目前移動端的招聘量確實變少了,但中高端的職位還是很多的,這說明行業只是變得成熟規範起來了。競爭越激烈,產品質量與留存就變得更加重要,我們進入了技術賦能業務的時代。

技術之路就是漫長的打怪升級,不斷學習前人的踩坑經驗才能提升自己,切忌閉門造車!所謂獨樂樂不如衆樂樂,在我當時確立好Android方向時,就已經開始梳理自己的成長路線了,包括技術要怎麼系統地去學習,都列得非常詳細,免費分享給大家。

從架構基礎開始,分了8個模塊來逐步從基礎進階到架構師的環節:

架構師築基語言基礎

目前Android APP開發主流語言就是Java語言,Java語言最大的特性就是提高了軟件的交互可能性,可以說安卓手機幾乎所有應用程序都是利用Java語言來進行編寫的。

設計思想解讀開源框架

隨着互聯網企業的不斷髮展,產品項目中的模塊越來越多,用戶體驗要求也越來越高,想實現小步快跑、快速迭代的目的越來越難,插件化技術應用而生。如果沒有插件化技術,美團、淘寶這些集成了大量“app”的應用,可能會有幾個g那麼大。

所以,當今的Android移動開發,不會熱修復、插件化、組件化,80%以上的面試都過不了。

360°全方位性能調優

在不同層次的開發工程師手裏,因爲技術水平的參差不齊,即使很多手機在跑分軟件性能非常高,打開應用依然存在卡頓現象。

另外,隨着產品內容迭代,功能越來越複雜,UI頁面也越來越豐富,也成爲流暢運行的一種阻礙。綜上所述,對APP進行性能優化已成爲開發者該有的一種綜合素質,也是開發者能夠完成高質量應用程序作品的保證。

Android框架體系架構

Android開發者也往往因爲網上Copy代碼習慣了而導致對這塊經常“使用”的代碼熟悉而又陌生:熟悉的是幾乎天天在和它們打交道, 天天在複製這些代碼 ;陌生的是雖然天天和這些代碼打交道,但是並沒有深入研究過這些代碼的原理,代碼深處的內涵。

NDK模塊開發(音視頻開發系列)

在Android中,NDK是一系列工具的集合,主要用於擴展Android SDK。NDK提供了一系列的工具可以幫助開發者快速的開發C或C++的動態庫,並能自動將so和Java應用一起打包成apk。

Flutter學習進階

自2020 年來無疑是 Flutter 技術如火如荼發展的一年。現在這門技術也依然非常有價值。

每一個移動開發者都在爲 Flutter 帶來的“快速開發、富有表現力和靈活的 UI、原生性能”的特色和理念而癡狂,從超級 App 到獨立應用,從純 Flutter 到混合棧,開發者們在不同的場景下樂此不疲的探索和應用着 Flutter 技術,也在面臨着各種各樣不同的挑戰。

微信小程序開發

微信小程序作爲現在比較火的編程開發應用場景之一,深受市場的青睞,這讓不少開發者眼饞不已。但是對於初學者來說,就完全摸不着頭腦了,不知道微信小程序開發製作需要學習那些知識,有需要的朋友可以參考本篇。

最後分享一份面試寶典,祝每個人面試順利。

Android BAT高級開發面試題及答案解析

面試的前一週時間內,就可以開始刷題衝刺了。請記住,刷題的時候,技術的優先,算法的看些基本的,比如排序等即可,而智力題,除非是校招,否則一般不怎麼會問。

以上內容均免費分享給大家,需要完整版的朋友,點這裏可以看到全部內容。或者點擊 【這裏】 查看獲取方式。

最後一些思考:

  • 我有時候經常會思考,以後Android開發該往什麼方向走?現在我們所掌握的技術以後會不會被替代淘汰?
  • 哪些方向會成爲絕對主流方向呢?
  • 像如今前景比較好的音視頻來說,並不是用Android去開發,而屬於NDK開發,用的C++語言。
  • Flutter跨平臺開發現在只是一種選擇,面試加分項,實際用的公司不多。
  • 人工智能方向,門檻對於大多Android開發來說很高,沒有相關專業的名校碩士學歷很難入場,對數據結構算法等要求很高。
  • 未來有點難以掌控的感覺。但是還好,可以掌控現在。技術無止境,不能停止學習。如果不能引領潮流,那就做一個跟隨者吧!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章