天天看點

Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結

*   **onUnBind()**:服務被解綁時調用;
*   **onDestroy()**:服務停止時調用;
           
  • 推薦文章:
    • Android元件系列----Android Service元件深入解析

2、Service的兩種啟動方式?差別在哪?

  • 參考回答:Service的兩種啟動模式
    • startService():通過這種方式調用startService,onCreate()隻會被調用一次,多次調用startSercie會多次執行onStartCommand()和onStart()方法。如果外部沒有調用stopService()或stopSelf()方法,service會一直運作。
    • bindService():如果該服務之前還沒建立,系統回調順序為onCreate()→onBind()。如果調用bindService()方法前服務已經被綁定,多次調用bindService()方法不會多次建立服務及綁定。如果調用者希望與正在綁定的服務解除綁定,可以調用unbindService()方法,回調順序為onUnbind()→onDestroy();
      Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結
  • 推薦文章:
    • Android Service兩種啟動方式詳解

3、如何保證Service不被殺死 ?

  • 參考回答:
    • onStartCommand方式中,傳回START_STICKY或則START_REDELIVER_INTENT
      • START_STICKY:如果傳回START_STICKY,表示Service運作的程序被Android系統強制殺掉之後,Android系統會将該Service依然設定為started狀态(即運作狀态),但是不再儲存onStartCommand方法傳入的intent對象
      • START_NOT_STICKY:如果傳回START_NOT_STICKY,表示當Service運作的程序被Android系統強制殺掉之後,不會重新建立該Service
      • START_REDELIVER_INTENT:如果傳回START_REDELIVER_INTENT,其傳回情況與START_STICKY類似,但不同的是系統會保留最後一次傳入onStartCommand方法中的Intent再次保留下來并再次傳入到重新建立後的Service的onStartCommand方法中
    • 提高Service的優先級 在AndroidManifest.xml檔案中對于intent-filter可以通過android:priority = "1000"這個屬性設定最高優先級,1000是最高值,如果數字越小則優先級越低,同時适用于廣播;
    • 在onDestroy方法裡重新開機Service 當service走到onDestroy()時,發送一個自定義廣播,當收到廣播時,重新啟動service;
    • 提升Service程序的優先級 程序優先級由高到低:前台程序 一 可視程序 一 服務程序 一 背景程序 一 空程序 可以使用startForeground将service放到前台狀态,這樣低記憶體時,被殺死的機率會低一些;
    • 系統廣播監聽Service狀态
    • 将APK安裝到/system/app,變身為系統級應用
  • 注意:以上機制都不能百分百保證Service不被殺死,除非做到系統白名單,與系統同生共死

4、能否在Service開啟耗時操作 ? 怎麼做 ?

  • 參考回答:
    • Service預設并不會運作在子線程中,也不運作在一個獨立的程序中,它同樣執行在主線程中(UI線程)。換句話說,不要在Service裡執行耗時操作,除非手動打開一個子線程,否則有可能出現主線程被阻塞(ANR)的情況;

5、用過哪些系統Service ?

  • 參考回答:
    Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結

6、了解ActivityManagerService嗎?發揮什麼作用

  • 參考回答: ActivityManagerService是Android中最核心的服務 , 主要負責系統中四大元件的啟動、切換、排程及應用程序的管理和排程等工作,其職責與作業系統中的程序管理和排程子產品類似;
  • 推薦文章:
    • ActivityManagerService分析——AMS啟動流程

Broadcast Receiver

1、廣播有幾種形式 ? 都有什麼特點 ?

  • 參考回答:
    • 普通廣播:開發者自身定義 intent的廣播(最常用),所有的廣播接收器幾乎會在同一時刻接受到此廣播資訊,接受的先後順序随機;
    • 有序廣播:發送出去的廣播被廣播接收者按照先後順序接收,同一時刻隻會有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執行完畢後,廣播才會繼續傳遞,且優先級(priority)高的廣播接收器會先收到廣播消息。有序廣播可以被接收器截斷使得後面的接收器無法收到它;
    • 本地廣播:僅在自己的應用内發送接收廣播,也就是隻有自己的應用能收到,資料更加安全,效率更高,但隻能采用動态注冊的方式;
    • 粘性廣播:這種廣播會一直滞留,當有比對該廣播的接收器被注冊後,該接收器就會收到此條廣播;
  • 推薦文章:
    • Android四大元件:BroadcastReceiver史上最全面解析

2、廣播的兩種注冊方式 ?

  • 參考回答:
    Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結

3、廣播發送和接收的原理了解嗎 ?(Binder機制、AMS)

  • 參考回答:
    Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結
  • 推薦文章:
    • 廣播的底層實作原理

ContentProvider

1、ContentProvider了解多少?

  • 參考回答:
    • ContentProvider作為四大元件之一,其主要負責存儲和共享資料。與檔案存儲、SharedPreferences存儲、SQLite資料庫存儲這幾種資料存儲方法不同的是,後者儲存下的資料隻能被該應用程式使用,而前者可以讓不同應用程式之間進行資料共享,它還可以選擇隻對哪一部分資料進行共享,進而保證程式中的隐私資料不會有洩漏風險。
  • 推薦文章:
    • Android:關于ContentProvider的知識都在這裡了!

2、ContentProvider的權限管理?

  • 參考回答:
    • 讀寫分離
    • 權限控制-精确到表級
    • URL控制

3、說說ContentProvider、ContentResolver、ContentObserver 之間的關系?

  • 參考回答:
    • ContentProvider:管理資料,提供資料的增删改查操作,資料源可以是資料庫、檔案、XML、網絡等,ContentProvider為這些資料的通路提供了統一的接口,可以用來做程序間資料共享。
    • ContentResolver:ContentResolver可以為不同URI操作不同的ContentProvider中的資料,外部程序可以通過ContentResolver與ContentProvider進行互動。
    • ContentObserver:觀察ContentProvider中的資料變化,并将變化通知給外界。

資料存儲

1、描述一下Android資料持久存儲方式?

  • 參考回答:Android平台實作資料持久存儲的常見幾種方式:
    • SharedPreferences存儲:一種輕型的資料存儲方式,本質是基于XML檔案存儲的key-value鍵值對資料,通常用來存儲一些簡單的配置資訊(如應用程式的各種配置資訊);
    • SQLite資料庫存儲:一種輕量級嵌入式資料庫引擎,它的運算速度非常快,占用資源很少,常用來存儲大量複雜的關系資料;
    • ContentProvider:四大元件之一,用于資料的存儲和共享,不僅可以讓不同應用程式之間進行資料共享,還可以選擇隻對哪一部分資料進行共享,可保證程式中的隐私資料不會有洩漏風險;
    • File檔案存儲:寫入和讀取檔案的方法和 Java中實作I/O的程式一樣;
    • 網絡存儲:主要在遠端的伺服器中存儲相關資料,使用者操作的相關資料可以同步到伺服器上;

2、SharedPreferences的應用場景?注意事項?

  • 參考回答:
    • SharedPreferences是一種輕型的資料存儲方式,本質是基于XML檔案存儲的key-value鍵值對資料,通常用來存儲一些簡單的配置資訊,如int,String,boolean、float和long;
    • 注意事項:
      • 勿存儲大型複雜資料,這會引起記憶體GC、阻塞主線程使頁面卡頓産生ANR
      • 勿在多程序模式下,操作Sp
      • 不要多次edit和apply,盡量批量修改一次送出
      • 建議apply,少用commit
  • 推薦文章:
    • 史上最全面,清晰的SharedPreferences解析
    • SharedPreferences在多程序中的使用及注意事項

3、SharedPrefrences的apply和commit有什麼差別?

  • 參考回答:
    • apply沒有傳回值而commit傳回boolean表明修改是否送出成功。
    • apply是将修改資料原子送出到記憶體, 而後異步真正送出到硬體磁盤, 而commit是同步的送出到硬體磁盤,是以,在多個并發的送出commit的時候,他們會等待正在處理的commit儲存到磁盤後在操作,進而降低了效率。而apply隻是原子的送出到内容,後面有調用apply的函數的将會直接覆寫前面的記憶體資料,這樣從一定程度上提高了很多效率。
    • apply方法不會提示任何失敗的提示。 由于在一個程序中,sharedPreference是單執行個體,一般不會出現并發沖突,如果對送出的結果不關心的話,建議使用apply,當然需要確定送出成功且有後續操作的話,還是需要用commit的。

4、了解SQLite中的事務操作嗎?是如何做的

  • 參考回答:
    • SQLite在做CRDU操作時都預設開啟了事務,然後把SQL語句翻譯成對應的SQLiteStatement并調用其相應的CRUD方法,此時整個操作還是在rollback journal這個臨時檔案上進行,隻有操作順利完成才會更新db資料庫,否則會被復原;

5、使用SQLite做批量操作有什麼好的方法嗎?

  • 參考回答:
    • 使用SQLiteDatabase的beginTransaction方法開啟一個事務,将批量操作SQL語句轉化為SQLiteStatement并進行批量操作,結束後endTransaction()

6、如何删除SQLite中表的個别字段

  • 參考回答:
    • SQLite資料庫隻允許增加字段而不允許修改和删除表字段,隻能建立新表保留原有字段,删除原表

7、使用SQLite時會有哪些優化操作?

  • 參考回答:
    • 使用事務做批量操作
    • 及時關閉Cursor,避免記憶體洩露
    • 耗時操作異步化:資料庫的操作屬于本地IO耗時操作,建議放入異步線程中處理
    • ContentValues的容量調整:ContentValues内部采用HashMap來存儲Key-Value資料,ContentValues初始容量為8,擴容時翻倍。是以建議對ContentValues填入的内容進行估量,設定合理的初始化容量,減少不必要的内部擴容操作
    • 使用索引加快檢索速度:對于查詢操作量級較大、業務對查詢要求較高的推薦使用索引

IPC

1、Android中程序和線程的關系? 差別?

  • 參考回答:
    • 線程是CPU排程的最小單元,同時線程是一種有限的系統資源
    • 程序一般指一個執行單元,在PC和移動裝置上一個程式或則一個應用
    • 一般來說,一個App程式至少有一個程序,一個程序至少有一個線程(包含與被包含的關系), 通俗來講就是,在App這個工廠裡面有一個程序,線程就是裡面的生産線,但主線程(主生産線)隻有一條,而子線程(副生産線)可以有多個
    • 程序有自己獨立的位址空間,而程序中的線程共享此位址空間,都可以并發執行
  • 推薦文章:
    • Android developer官方文檔–程序和線程

2、如何開啟多程序 ? 應用是否可以開啟N個程序 ?

  • 參考回答:
    • 在AndroidMenifest中給四大元件指定屬性android:process開啟多程序模式
    • 在記憶體允許的條件下可以開啟N個程序
  • 推薦講解:
    • 如何開啟多程序?應用是否可以開啟N個程序?

3、為何需要IPC?多程序通信可能會出現的問題?

  • 參考回答:
    • 所有運作在不同程序的四大元件(Activity、Service、Receiver、ContentProvider)共享資料都會失敗,這是由于Android為每個應用配置設定了獨立的虛拟機,不同的虛拟機在記憶體配置設定上有不同的位址空間,這會導緻在不同的虛拟機中通路同一個類的對象會産生多份副本。比如常用例子(通過開啟多程序擷取更大記憶體空間、兩個或則多個應用之間共享資料、微信全家桶)
    • 一般來說,使用多程序通信會造成如下幾方面的問題
      • 靜态成員和單例模式完全失效:獨立的虛拟機造成
      • 線程同步機制完全實效:獨立的虛拟機造成
      • SharedPreferences的可靠性下降:這是因為Sp不支援兩個程序并發進行讀寫,有一定幾率導緻資料丢失
      • Application會多次建立:Android系統在建立新的程序會配置設定獨立的虛拟機,是以這個過程其實就是啟動一個應用的過程,自然也會建立新的Application
  • 推薦文章:
    • Android developer官方文檔–程序和線程

4、Android中IPC方式、各種方式優缺點,為什麼選擇Binder?

  • 參考回答:

    [外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-2pMKcpah-1630835555986)(https://user-gold-cdn.xitu.io/2019/3/8/1695c1ab2aabf780?imageView2/0/w/1280/h/960/ignore-error/1)]

    與Linux上傳統的IPC機制,比如System V,Socket相比,Binder好在哪呢?

    • 傳輸效率高、可操作性強:傳輸效率主要影響因素是記憶體拷貝的次數,拷貝次數越少,傳輸速率越高。從Android程序架構角度分析:對于消息隊列、Socket和管道來說,資料先從發送方的緩存區拷貝到核心開辟的緩存區中,再從核心緩存區拷貝到接收方的緩存區,一共兩次拷貝,如圖:
      Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結
      而對于Binder來說,資料從發送方的緩存區拷貝到核心的緩存區,而接收方的緩存區與核心的緩存區是映射到同一塊實體位址的,節省了一次資料拷貝的過程,如圖:
      Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結
      由于共享記憶體操作複雜,綜合來看,Binder的傳輸效率是最好的。
    • 實作C/S架構友善:Linux的衆IPC方式除了Socket以外都不是基于C/S架構,而Socket主要用于網絡間的通信且傳輸效率較低。Binder基于C/S架構 ,Server端與Client端相對獨立,穩定性較好。
    • 安全性高:傳統Linux IPC的接收方無法獲得對方程序可靠的UID/PID,進而無法鑒别對方身份;而Binder機制為每個程序配置設定了UID/PID且在Binder通信時會根據UID/PID進行有效性檢測。
  • 推薦文章:
    • 為什麼 Android 要采用 Binder 作為 IPC 機制?

5、Binder機制的作用和原理?

  • 參考回答:
    • Linux系統将一個程序分為使用者空間和核心空間。對于程序之間來說,使用者空間的資料不可共享,核心空間的資料可共享,為了保證安全性和獨立性,一個程序不能直接操作或者通路另一個程序,即Android的程序是互相獨立、隔離的,這就需要跨程序之間的資料通信方式
      Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結
  • 一次完整的 Binder IPC 通信過程通常是這樣:
    • 首先 Binder 驅動在核心空間建立一個資料接收緩存區;
    • 接着在核心空間開辟一塊核心緩存區,建立核心緩存區和核心中資料接收緩存區之間的映射關系,以及核心中資料接收緩存區和接收程序使用者空間位址的映射關系;
    • 發送方程序通過系統調用 copyfromuser() 将資料 copy 到核心中的核心緩存區,由于核心緩存區和接收程序的使用者空間存在記憶體映射,是以也就相當于把資料發送到了接收程序的使用者空間,這樣便完成了一次程序間的通信。
      Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結

6、Binder架構中ServiceManager的作用?

  • 參考回答:
    • Binder架構 是基于 C/S 架構的。由一系列的元件組成,包括 Client、Server、ServiceManager、Binder驅動,其中 Client、Server、Service Manager 運作在使用者空間,Binder 驅動運作在核心空間
      Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結
      • Server&Client:伺服器&用戶端。在Binder驅動和Service Manager提供的基礎設施上,進行Client-Server之間的通信。
      • ServiceManager(如同DNS域名伺服器)服務的管理者,将Binder名字轉換為Client中對該Binder的引用,使得Client可以通過Binder名字獲得Server中Binder實體的引用。
      • Binder驅動(如同路由器):負責程序之間binder通信的建立,傳遞,計數管理以及資料的傳遞互動等底層支援。
        Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結
        圖檔出自Carson_Ho文章 —— Android跨程序通信:圖文詳解 Binder機制 原理

7、Bundle傳遞對象為什麼需要序列化?Serialzable和Parcelable的差別?

  • 參考回答:
    • 因為bundle傳遞資料時隻支援基本資料類型,是以在傳遞對象時需要序列化轉換成可存儲或可傳輸的本質狀态(位元組流)。序列化後的對象可以在網絡、IPC(比如啟動另一個程序的Activity、Service和Reciver)之間進行傳輸,也可以存儲到本地。
    • 序列化實作的兩種方式:實作Serializable/Parcelable接口。不同點如圖:

      [外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-wv47VxUS-1630835555991)(https://user-gold-cdn.xitu.io/2019/3/8/1695c349f019c41f?imageView2/0/w/1280/h/960/ignore-error/1)]

8、講講AIDL?原理是什麼?如何優化多子產品都使用AIDL的情況?

  • 參考回答:
    • AIDL(Android Interface Definition Language,Android接口定義語言):如果在一個程序中要調用另一個程序中對象的方法,可使用AIDL生成可序列化的參數,AIDL會生成一個服務端對象的代理類,通過它用戶端實作間接調用服務端對象的方法。
    • AIDL的本質是系統提供了一套可快速實作Binder的工具。關鍵類和方法:
      • AIDL接口:繼承IInterface。
      • Stub類:Binder的實作類,服務端通過這個類來提供服務。
      • Proxy類:伺服器的本地代理,用戶端通過這個類調用伺服器的方法。
      • asInterface():用戶端調用,将服務端的傳回的Binder對象,轉換成用戶端所需要的AIDL接口類型對象。如果用戶端和服務端位于統一程序,則直接傳回Stub對象本身,否則傳回系統封裝後的Stub.proxy對象
      • asBinder():根據目前調用情況傳回代理Proxy的Binder對象。
      • onTransact():運作服務端的Binder線程池中,當用戶端發起跨程序請求時,遠端請求會通過系統底層封裝後交由此方法來處理。
      • transact():運作在用戶端,當用戶端發起遠端請求的同時将目前線程挂起。之後調用服務端的onTransact()直到遠端請求傳回,目前線程才繼續執行。
    • 當有多個業務子產品都需要AIDL來進行IPC,此時需要為每個子產品建立特定的aidl檔案,那麼相應的Service就會很多。必然會出現系統資源耗費嚴重、應用過度重量級的問題。解決辦法是建立Binder連接配接池,即将每個業務子產品的Binder請求統一轉發到一個遠端Service中去執行,進而避免重複建立Service。
      • 工作原理:每個業務子產品建立自己的AIDL接口并實作此接口,然後向服務端提供自己的唯一辨別和其對應的Binder對象。服務端隻需要一個Service,伺服器提供一個queryBinder接口,它會根據業務子產品的特征來傳回相應的Binder對象,不同的業務子產品拿到所需的Binder對象後就可進行遠端方法的調用了

View

1、講下View的繪制流程?

  • 參考回答:
    • View的工作流程主要是指measure、layout、draw這三大流程,即測量、布局和繪制,其中measure确定View的測量寬/高,layout确定View的最終寬/高和四個頂點的位置,而draw則将View繪制到螢幕上
    • View的繪制過程遵循如下幾步:
      • 繪制背景 background.draw(canvas)
      • 繪制自己(onDraw)
      • 繪制 children(dispatchDraw)
      • 繪制裝飾(onDrawScollBars)
        Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結
  • 推薦文章:
    • 官方文檔
    • Android View的繪制流程
    • Android應用層View繪制流程與源碼分析

2、MotionEvent是什麼?包含幾種事件?什麼條件下會産生?

  • 參考回答:
    • MotionEvent是手指接觸螢幕後所産生的一系列事件。典型的事件類型有如下:
      • ACTION_DOWN:手指剛接觸螢幕
      • ACTION_MOVE:手指在螢幕上移動
      • ACTION_UP:手指從螢幕上松開的一瞬間
      • ACTION_CANCELL:手指保持按下操作,并從目前控件轉移到外層控件時觸發
    • 正常情況下,一次手指觸摸螢幕的行為會觸發一系列點選事件,考慮如下幾種情況:
      • 點選螢幕後松開,事件序列:DOWN→UP
      • 點選螢幕滑動一會再松開,事件序列為DOWN→MOVE→…→MOVE→UP

3、描述一下View事件傳遞分發機制?

  • 參考回答:
    • View事件分發本質就是對MotionEvent事件分發的過程。即當一個MotionEvent發生後,系統将這個點選事件傳遞到一個具體的View上
    • 點選事件的傳遞順序:Activity(Window)→ViewGroup→ View
    • 事件分發過程由三個方法共同完成:
      • dispatchTouchEvent:用來進行事件的分發。如果事件能夠傳遞給目前View,那麼此方法一定會被調用,傳回結果受目前View的onTouchEvent和下級View的dispatchTouchEvent方法的影響,表示是否消耗目前事件
      • onInterceptTouchEvent:在上述方法内部調用,對事件進行攔截。該方法隻在ViewGroup中有,View(不包含 ViewGroup)是沒有的。一旦攔截,則執行ViewGroup的onTouchEvent,在ViewGroup中處理事件,而不接着分發給View。且隻調用一次,傳回結果表示是否攔截目前事件
      • onTouchEvent: 在dispatchTouchEvent方法中調用,用來處理點選事件,傳回結果表示是否消耗目前事件

4、如何解決View的事件沖突 ? 舉個開發中遇到的例子 ?

  • 參考回答:
    • 常見開發中事件沖突的有ScrollView與RecyclerView的滑動沖突、RecyclerView内嵌同時滑動同一方向
    • 滑動沖突的處理規則:
      • 對于由于外部滑動和内部滑動方向不一緻導緻的滑動沖突,可以根據滑動的方向判斷誰來攔截事件。
      • 對于由于外部滑動方向和内部滑動方向一緻導緻的滑動沖突,可以根據業務需求,規定何時讓外部View攔截事件,何時由内部View攔截事件。
      • 對于上面兩種情況的嵌套,相對複雜,可同樣根據需求在業務上找到突破點。
    • 滑動沖突的實作方法:
      • 外部攔截法:指點選事件都先經過父容器的攔截處理,如果父容器需要此事件就攔截,否則就不攔截。具體方法:需要重寫父容器的onInterceptTouchEvent方法,在内部做出相應的攔截。
      • 内部攔截法:指父容器不攔截任何事件,而将所有的事件都傳遞給子容器,如果子容器需要此事件就直接消耗,否則就交由父容器進行處理。具體方法:需要配合requestDisallowInterceptTouchEvent方法。

5、scrollTo()和scollBy()的差別?

  • 參考回答:
    • scollBy内部調用了scrollTo,它是基于目前位置的相對滑動;而scrollTo是絕對滑動,是以如果使用相同輸入參數多次調用scrollTo方法,由于View的初始位置是不變的,是以隻會出現一次View滾動的效果

總結

最後對于程式員來說,要學習的知識内容、技術有太多太多,要想不被環境淘汰就隻有不斷提升自己,從來都是我們去适應環境,而不是環境來适應我們!

這裡附上上述的技術體系圖相關的幾十套騰訊、頭條、阿裡、美團等公司20年的面試題,把技術點整理成了視訊和PDF(實際上比預期多花了不少精力),包含知識脈絡 + 諸多細節,由于篇幅有限,這裡以圖檔的形式給大家展示一部分。

相信它會給大家帶來很多收獲:

Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結
Android篇:2019國中級Android開發社招面試解答,位元組跳動面試分享總結
本文在**CodeChina開源項目:《Android學習筆記總結+移動架構視訊+大廠面試真題+項目實戰源碼》**中已收錄,裡面包含不同方向的自學程式設計路線、面試題集合/面經、及系列技術文章等,資源持續更新中…
當程式員容易,當一個優秀的程式員是需要不斷學習的,從初級程式員到進階程式員,從初級架構師到資深架構師,或者走向管理,從技術經理到技術總監,每個階段都需要掌握不同的能力。早早确定自己的職業方向,才能在工作和能力提升中甩開同齡人。

3)]

[外鍊圖檔轉存中…(img-QXT7dTBK-1630835555993)]

本文在**CodeChina開源項目:《Android學習筆記總結+移動架構視訊+大廠面試真題+項目實戰源碼》**中已收錄,裡面包含不同方向的自學程式設計路線、面試題集合/面經、及系列技術文章等,資源持續更新中…
當程式員容易,當一個優秀的程式員是需要不斷學習的,從初級程式員到進階程式員,從初級架構師到資深架構師,或者走向管理,從技術經理到技術總監,每個階段都需要掌握不同的能力。早早确定自己的職業方向,才能在工作和能力提升中甩開同齡人。