<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試了 OPPO ,才發(fā)現(xiàn)我如此之菜!

          共 9371字,需瀏覽 19分鐘

           ·

          2021-10-17 10:55

          點(diǎn)擊“開發(fā)者技術(shù)前線”,選擇“星標(biāo)??”

          讓一部分開發(fā)者看到未來


          來源?|?公眾號(hào) 劉望舒 文?| AffyFei

          責(zé)編:可可??

          導(dǎo)讀

          本文中的經(jīng)歷是作者AffyFei,不是"我,下面看正文:

          今天早上參加了深圳OPPO開發(fā)工程師的技術(shù)面試,總的來說面試過程不是很順利。面試官并沒有問一些很深?yuàn)W的底層原理,基本都是一些Java基礎(chǔ)以及Android四大組件內(nèi)的基礎(chǔ),但是我自身在開發(fā)過程中并沒有很重視這些理論基礎(chǔ),導(dǎo)致很多知識(shí)點(diǎn)都忘記了。整個(gè)面試過程耗時(shí)一小時(shí),感謝兩位面試官不厭其煩地給我提示,一方面讓我能夠回想起來那些遺忘的知識(shí)點(diǎn),另一方面也緩解了尷尬的氣氛。  

          順便一說,OPPO的保密工作還是做得比較嚴(yán)格的,進(jìn)去后海卓越中心大樓前需要申請(qǐng)臨時(shí)通行證才能進(jìn)去。而在面試前還需要登記,并且把手機(jī)的前后攝像頭都給用膠帶封起來才能進(jìn)行面試。廢話少說,下面分成兩部分匯總一下這次技術(shù)面試的知識(shí)點(diǎn)。

          Java方面

          1、如何理解Java的多態(tài)?其中,重載和重寫有什么區(qū)別?

          多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力,多態(tài)是同一個(gè)接口,使用不同的實(shí)例而執(zhí)行不同操作,多態(tài)就是程序運(yùn)行期間才確定,一個(gè)引用變量倒底會(huì)指向哪個(gè)類的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類中實(shí)現(xiàn)的方法。
          多態(tài)存在的三個(gè)必要條件是:繼承,重寫,父類引用指向子類引用。
          多態(tài)的三個(gè)實(shí)現(xiàn)方式是:重寫,接口,抽象類和抽象方法。
          重寫(Override)和重載(Overload)的區(qū)別

          2、談一下JVM內(nèi)存區(qū)域劃分?哪部分是線程公有的,哪部分是私有的?

          JVM 的內(nèi)存區(qū)域可以分為兩類:線程私有和區(qū)域和線程共有的區(qū)域。線程私有的區(qū)域:程序計(jì)數(shù)器、JVM 虛擬機(jī)棧、本地方法棧;線程共有的區(qū)域:堆、方法區(qū)、運(yùn)行時(shí)常量池。

          程序計(jì)數(shù)器,也有稱作PC寄存器。每個(gè)線程都有一個(gè)私有的程序計(jì)數(shù)器,任何時(shí)間一個(gè)線程都只會(huì)有一個(gè)方法正在執(zhí)行,也就是所謂的當(dāng)前方法。程序計(jì)數(shù)器存放的就是這個(gè)當(dāng)前方法的JVM指令地址。當(dāng)CPU需要執(zhí)行指令時(shí),需要從程序計(jì)數(shù)器中得到當(dāng)前需要執(zhí)行的指令所在存儲(chǔ)單元的地址,然后根據(jù)得到的地址獲取到指令,在得到指令之后,程序計(jì)數(shù)器便自動(dòng)加1或者根據(jù)轉(zhuǎn)移指針得到下一條指令的地址,如此循環(huán),直至執(zhí)行完所有的指令。

          JVM虛擬機(jī)棧。創(chuàng)建線程的時(shí)候會(huì)創(chuàng)建線程內(nèi)的虛擬機(jī)棧,棧中存放著一個(gè)個(gè)的棧幀,對(duì)應(yīng)著一個(gè)個(gè)方法的調(diào)用。JVM 虛擬機(jī)棧有兩種操作,分別是壓棧和出站。棧幀中存放著局部變量表(Local Variables)、操作數(shù)棧(Operand Stack)、指向當(dāng)前方法所屬的類的運(yùn)行時(shí)常量池的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些額外的附加信息。

          本地方法棧。本地方法棧與Java棧的作用和原理非常相似。區(qū)別只不過是Java棧是為執(zhí)行Java方法服務(wù)的,而本地方法棧則是為執(zhí)行本地方法(Native Method)服務(wù)的。在JVM規(guī)范中,并沒有對(duì)本地方發(fā)展的具體實(shí)現(xiàn)方法以及數(shù)據(jù)結(jié)構(gòu)作強(qiáng)制規(guī)定,虛擬機(jī)可以自由實(shí)現(xiàn)它。在HotSopt虛擬機(jī)中直接就把本地方法棧和Java棧合二為一。

          堆。堆是內(nèi)存管理的核心區(qū)域,用來存放對(duì)象實(shí)例。幾乎所有創(chuàng)建的對(duì)象實(shí)例都會(huì)直接分配到堆上。所以堆也是垃圾回收的主要區(qū)域,垃圾收集器會(huì)對(duì)堆有著更細(xì)的劃分,最常見的就是把堆劃分為新生代和老年代。java堆允許處于不連續(xù)的物理內(nèi)存空間中,只要邏輯連續(xù)即可。堆中如果沒有空間完成實(shí)例分配無法擴(kuò)展時(shí)將會(huì)拋出OutOfMemoryError異常。

          方法區(qū)。方法區(qū)與堆一樣所有線程所共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、及時(shí)編譯器編譯后的代碼等數(shù)據(jù)。在Class文件中除了類的字段、方法、接口等描述信息外,還有一項(xiàng)信息是常量池,用來存儲(chǔ)編譯期間生成的字面量和符號(hào)引用。
          其實(shí)除了程序計(jì)數(shù)器,其他的部分都會(huì)發(fā)生 OOM。

          堆。通常發(fā)生的 OOM 都會(huì)發(fā)生在堆中,最常見的可能導(dǎo)致 OOM 的原因就是內(nèi)存泄漏。
          JVM虛擬機(jī)棧和本地方法棧。當(dāng)我們寫一個(gè)遞歸方法,這個(gè)遞歸方法沒有循環(huán)終止條件,最終會(huì)導(dǎo)致 ?StackOverflow 的錯(cuò)誤。當(dāng)然,如果??臻g擴(kuò)展失敗,也是會(huì)發(fā)生 OOM 的。
          方法區(qū)。方法區(qū)現(xiàn)在基本上不太會(huì)發(fā)生 OOM,但在早期內(nèi)存中加載的類信息過多的情況下也是會(huì)發(fā)生 OOM 的。

          3、final關(guān)鍵字的用法?

          final 可以修飾類、變量和方法。修飾類代表這個(gè)類不可被繼承。修飾變量代表此變量不可被改變。修飾方法表示此方法不可被重寫 (override)。

          4、死鎖是怎么導(dǎo)致的?如何定位死鎖

          某個(gè)任務(wù)在等待另一個(gè)任務(wù),而后者又等待別的任務(wù),這樣一直下去,直到這個(gè)鏈條上的任務(wù)又在等待第一個(gè)任務(wù)釋放鎖。這得到了一個(gè)任務(wù)之間互相等待的連續(xù)循環(huán),沒有哪個(gè)線程能繼續(xù)。這被稱之為死鎖。當(dāng)以下四個(gè)條件同時(shí)滿足時(shí),就會(huì)產(chǎn)生死鎖:
          (1) 互斥條件。任務(wù)所使用的資源中至少有一個(gè)是不能共享的。
          (2) 任務(wù)必須持有一個(gè)資源,同時(shí)等待獲取另一個(gè)被別的任務(wù)占有的資源。
          (3) 資源不能被強(qiáng)占。
          (4) 必須有循環(huán)等待。一個(gè)任務(wù)正在等待另一個(gè)任務(wù)所持有的資源,后者又在等待別的任務(wù)所持有的資源,這樣一直下去,直到有一個(gè)任務(wù)在等待第一個(gè)任務(wù)所持有的資源,使得大家都被鎖住。
          要解決死鎖問題,必須打破上面四個(gè)條件的其中之一。在程序中,最容易打破的往往是第四個(gè)條件。

          5、數(shù)據(jù)庫如何進(jìn)行升級(jí)?SQLite增刪改查的基礎(chǔ)sql語句?

          ????public?SQLiteOpenHelper(Context?context,?String?name,?CursorFactory?factory,?int?version)?{
          ????????this(context,?name,?factory,?version,?null);
          ????}

          ????public?SQLiteDatabase?getWritableDatabase()?{
          ????????synchronized?(this)?{
          ????????????return?getDatabaseLocked(true);
          ????????}
          ????}

          ??private?SQLiteDatabase?getDatabaseLocked(boolean?writable)?{
          ??????.......
          ??????db.beginTransaction();
          ??????try?{
          ??????????????if?(version?==?0)?{
          ???????????????????onCreate(db);
          ??????????????}?else?{
          ???????????????????if?(version?>?mNewVersion)?{
          ?????????????????????????onDowngrade(db,?version,?mNewVersion);
          ???????????????????}?else?{
          ?????????????????????????onUpgrade(db,?version,?mNewVersion);
          ???????????????????}
          ??????????????}
          ???????????????db.setVersion(mNewVersion);
          ????????????????db.setTransactionSuccessful();
          ??????????????}?finally?{
          ?????????????????db.endTransaction();
          ??????????????}
          ??}

          在SQLiteOpenHelper的構(gòu)造函數(shù)中,包含了一個(gè)version的參數(shù)。這個(gè)參數(shù)即是數(shù)據(jù)庫的版本。所以,我們可以通過修改version來實(shí)現(xiàn)數(shù)據(jù)庫的升級(jí)。當(dāng)version大于原數(shù)據(jù)庫版本時(shí),onUpgrade()會(huì)被觸發(fā),可以在該方法中編寫數(shù)據(jù)庫升級(jí)邏輯。具體的數(shù)據(jù)庫升級(jí)邏輯示例可參考這里。
          常用的SQL增刪改查:

          • 增:INSERT INTO table_name (列1, 列2,…) VALUES (值1, 值2,….)

          • 刪:DELETE FROM 表名稱 WHERE 列名稱 = 值

          • 改:UPDATE 表名稱 SET 列名稱 = 新值 WHERE 列名稱 = 某值

          • 查:SELECT 列名稱(通配是*符號(hào)) FROM 表名稱

          ps:操作數(shù)據(jù)表是:ALTER TABLE。該語句用于在已有的表中添加、修改或刪除列。
          ALTER TABLE table_name ADD column_name datatype
          ALTER TABLE table_name DROP COLUMN column_name
          ALTER TABLE table_name_old RENAME TO table_name_new

          Android方面

          1、Broadcast的分類?有序,無序?粘性,非粘性?本地廣播?

          廣播可以分為有序廣播、無序廣播、本地廣播、粘性廣播。其中無序廣播通過sendBroadcast(intent)發(fā)送,有序廣播通過sendOrderedBroadcast(intent)發(fā)送。

          有序廣播
          (1) 有序廣播可以用priority來調(diào)整優(yōu)先級(jí) ? 取值范圍-1000~+1000,默認(rèn)為0,數(shù)值越大優(yōu)先級(jí)越高,優(yōu)先級(jí)越高越優(yōu)先獲得廣播響應(yīng)。
          (2) abortBroadcast()可來終止該廣播的傳播,對(duì)更低優(yōu)先級(jí)的屏蔽,注意只對(duì)有序廣播生效。
          (3) 有序廣播在傳播數(shù)據(jù)中會(huì)發(fā)生比如setResultData(),getResultData(),在傳播過程中,可以從新設(shè)置數(shù)據(jù)

          關(guān)于本地廣播,可以查看這篇文章??偟膩碚f,本地廣播是通過LocalBroadcastManager內(nèi)置的Handler來實(shí)現(xiàn)的,只是利用了IntentFilter的match功能,至于BroadcastReceiver 換成其他接口也無所謂,順便利用了現(xiàn)成的類和概念而已。在register()的時(shí)候保存BroadcastReceiver以及對(duì)應(yīng)的IntentFilter,在sendBroadcast()的時(shí)候找到和Intent對(duì)應(yīng)的BroadcastReceiver,然后通過Handler發(fā)送消息,觸發(fā)executePendingBroadcasts()函數(shù),再在后者中調(diào)用對(duì)應(yīng)BroadcastReceiver的onReceive()方法。

          粘性消息:粘性消息在發(fā)送后就一直存在于系統(tǒng)的消息容器里面,等待對(duì)應(yīng)的處理器去處理,如果暫時(shí)沒有處理器處理這個(gè)消息則一直在消息容器里面處于等待狀態(tài),粘性廣播的Receiver如果被銷毀,那么下次重建時(shí)會(huì)自動(dòng)接收到消息數(shù)據(jù)。(在 android 5.0/api 21中deprecated,不再推薦使用,相應(yīng)的還有粘性有序廣播,同樣已經(jīng)deprecated)

          2、Android中的事件傳遞機(jī)制?

          當(dāng)我們的手指觸碰到屏幕,事件是按照Activity->ViewGroup->View這樣的流程到達(dá)最終響應(yīng)觸摸事件的View的。而在事件分發(fā)過程中,涉及到三個(gè)最重要的方法:dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent。我們的手指觸摸到屏幕的時(shí)候,會(huì)觸發(fā)一個(gè)Action_Down類型的事件,當(dāng)前頁面的Activity會(huì)首先做出相應(yīng),也就是說會(huì)走到Activity的dispatchTouchEvent()方法內(nèi)。在這個(gè)方法內(nèi)部有下面兩個(gè)邏輯:

          調(diào)用getWindow.superDispatchTouchEvent()。如果上一步返回true,則直接返回true;否則return自己的onTouchEvent()。顯然,當(dāng)getWindow.superDispatchTouchEvent()返回true,表示當(dāng)前事件已經(jīng)被消費(fèi)掉,無需調(diào)用onTouchEvent;否則代表事件并沒有被處理,因此需要調(diào)用Activity的onTouchEvent進(jìn)行處理。我們都知道,getWindow()返回的是PhoneWindow,因此這句代碼本質(zhì)上調(diào)用了PhoneWindow中的superDispatchTouchEvent()。而后者實(shí)際上調(diào)用了mDecor.superDispatchTouchEvent(event)。這個(gè)mDecor也就是DecorView,它是FrameLayout的一個(gè)子類。在DecorView中的superDispatchTouchEvent(event)中調(diào)用的是super.dispatchTouchEvent()。因此,本質(zhì)上調(diào)用的是ViewGroup的dispatchTouchEvent()。

          到這里,事件已經(jīng)從Activity傳遞到ViewGroup了。接下來我們分析ViewGroup。在ViewGroup的dispatchTouchEvent()中邏輯大致如下:

          通過onInterceptTouchEvent()判斷當(dāng)前ViewGroup是否攔截,默認(rèn)的ViewGroup都是不攔截的;
          如果攔截,則return自己的onTouchEvent();如果不攔截,則根據(jù)child.dispatchTouchEvent()的返回值判斷。如果返回true,則return true;否則return自身的onTouchEvent(),在這里實(shí)現(xiàn)了未處理事件的向上傳遞。通常情況下,ViewGroup的onInterceptTouchEvent()都返回false,表示不攔截。這里需要注意的是事件序列,比如Down事件、Move事件…Up事件,從Down到Up是一個(gè)完整的事件序列,對(duì)應(yīng)著手指從按下到抬起這一系列事件,如果ViewGroup攔截了Down事件,那么后續(xù)事件都會(huì)交給這個(gè)ViewGroup的onTouchEvent。如果ViewGroup攔截的不是Down事件,那么會(huì)給之前處理這個(gè)Down事件的View發(fā)送一個(gè)Action_Cancel類型的事件,通知子View這個(gè)后續(xù)的事件序列已經(jīng)被ViewGroup接管了,子View恢復(fù)之前的狀態(tài)即可。

          這里舉一個(gè)常見的例子:在一個(gè) Recyclerview 中有很多的 Button,我們首先按下了一個(gè) button,然后滑動(dòng)一段距離再松開,這時(shí)候 Recyclerview 會(huì)跟著滑動(dòng),并不會(huì)觸發(fā)這個(gè) button 的點(diǎn)擊事件。這個(gè)例子中,當(dāng)我們按下 button 時(shí),這個(gè) button 接收到了 Action_Down 事件,正常情況下后續(xù)的事件序列應(yīng)該由這個(gè) button處理。但我們滑動(dòng)了一段距離,這時(shí) ?Recyclerview 察覺到這是一個(gè)滑動(dòng)操作,攔截了這個(gè)事件序列,走了自身的 onTouchEvent()方法,反映在屏幕上就是列表的滑動(dòng)。而這時(shí) button 仍然處于按下的狀態(tài),所以在攔截的時(shí)候需要發(fā)送一個(gè) Action_Cancel 來通知 button 恢復(fù)之前狀態(tài)。

          事件分發(fā)最終會(huì)走到View的dispatchTouchEvent()中。在View的dispatchTouchEvent()中沒有onInterceptTouchEvent(),這里很容易理解,View沒有child,也就不存在攔截。View的dispatchTouchEvent()直接return了自己的onTouchEvent()。如果onTouchEvent()返回true代表事件被消費(fèi),否則未消費(fèi)的事件會(huì)向上傳遞,直到有View處理了事件或一直沒有消費(fèi),最終回到Activity的onTouchEvent()終止。有時(shí)候會(huì)有人混淆onTouchEvent和onTouch。首先,這兩個(gè)方法都在View的dispatchTouchEvent()中:

          如果touchListener不為null,并且這個(gè)View是enable的,而且onTouch返回true,都滿足時(shí)直接return true,走不到onTouchEvent()方法。否則,就會(huì)觸發(fā)onTouchEvent()。因此onTouch優(yōu)先于onTouchEvent獲得事件處理權(quán)。
          最后附上流程圖總結(jié):

          參考:https://juejin.im/entry/58df5b33570c35005798493c
          https://juejin.im/post/5b8f15e26fb9a01a031b12d9#heading-3

          3、Handler的原理?
          與Handler密切相關(guān)的還有Message、MessageQueue、Looper。

          Message。Message有兩個(gè)關(guān)鍵的成員變量:target、callback:
          (1) target。就是發(fā)送消息的Handler
          (2) callback。調(diào)用Handler.post(Runnable)時(shí)傳入的Runnable類型的任務(wù)。post事件的本質(zhì)也是創(chuàng)建了一個(gè)Message,將我們傳入的這個(gè)runnable賦值給創(chuàng)建的Message的callback這個(gè)成員變量。
          MessageQueue。消息隊(duì)列用于存放消息,其中重點(diǎn)關(guān)注next()方法,它會(huì)返回下一個(gè)待處理的消息。
          Looper。Looper消息輪詢器其實(shí)是連接Handler和消息隊(duì)列的核心。想要在一個(gè)線程中創(chuàng)建一個(gè)Handler,首先要通過Looper.prepare()創(chuàng)建Looper,之后還得調(diào)用Looper.loop()開啟輪詢。
          (1) prepare()。這個(gè)方法做了兩件事:首先通過ThreadLocal.get()獲取當(dāng)前線程中的Looper,如果不為空則拋出RuntimeException。否則創(chuàng)建Looper,并通過ThreadLocal.set(looper)將當(dāng)前線程與剛剛創(chuàng)建的Looper綁定。值得注意的是,上面的消息隊(duì)列的創(chuàng)建其實(shí)就是發(fā)生在Looper的構(gòu)造函數(shù)中。
          (2)loop()。這個(gè)方法開啟了整個(gè)事件機(jī)制的輪詢。其本質(zhì)是開啟一個(gè)死循環(huán),不斷地通過MessageQueue的next()方法獲取消息msg。拿到消息后會(huì)調(diào)用msg.target.dispatchMessage()來做處理。綜上也就是調(diào)用handler.dispatchMessage()。
          Handler。Handler重點(diǎn)在于發(fā)送消息和處理消息。
          (1)發(fā)送消息。其實(shí)發(fā)送消息除了 sendMessage 之外還有 sendMessageDelayed 和 post 以及 postDelayed 等等不同的方式。但它們的本質(zhì)都是調(diào)用了 sendMessageAtTime。在 sendMessageAtTime 這個(gè)方法中調(diào)用了 enqueueMessage。在 enqueueMessage 這個(gè)方法中做了兩件事:通過 msg.target = this 實(shí)現(xiàn)了消息與當(dāng)前 handler 的綁定。然后通過 queue.enqueueMessage 實(shí)現(xiàn)了消息入隊(duì)。
          (2)處理消息。消息處理的核心其實(shí)就是dispatchMessage()這個(gè)方法。這個(gè)方法里面的邏輯很簡(jiǎn)單,先判斷 msg.callback 是否為 null,如果不為空則執(zhí)行這個(gè) runnable。如果為空則會(huì)執(zhí)行我們的handleMessage方法。

          4、ANR出現(xiàn)的情況有幾種?怎么分析解決ANR問題?

          ANR(Application Not responding)。Android中,主線程(UI線程)如果在規(guī)定時(shí)內(nèi)沒有處理完相應(yīng)工作,就會(huì)出現(xiàn)ANR。具體來說,ANR會(huì)在以下幾種情況中出現(xiàn):
          (1) 輸入事件(按鍵和觸摸事件)5s內(nèi)沒被處理
          (2) BroadcastReceiver的事件(onRecieve方法)在規(guī)定時(shí)間內(nèi)沒處理完(前臺(tái)廣播為10s,后臺(tái)廣播為60s)
          (3) service 前臺(tái)20s后臺(tái)200s未完成啟動(dòng)
          (4) ContentProvider的publish在10s內(nèi)沒進(jìn)行完

          分析ANR問題,需要結(jié)合Log以及trace文件。具體分析流程,可參照以下兩篇文章:
          https://www.jianshu.com/p/fa962a5fd939
          https://blog.csdn.net/droyon/article/details/51099826

          5、內(nèi)存泄露的場(chǎng)景有哪些??jī)?nèi)存泄漏分析工具使用方法?

          常見的內(nèi)存泄露有:

          • 單例模式引起的內(nèi)存泄露。

          • 靜態(tài)變量導(dǎo)致的內(nèi)存泄露。

          • 非靜態(tài)內(nèi)部類引起的內(nèi)存泄露。

          • 使用資源時(shí),未及時(shí)關(guān)閉引起內(nèi)存泄露。

          • 使用屬性動(dòng)畫引起的內(nèi)存泄露。

          • Webview導(dǎo)致的內(nèi)存泄露。

          而對(duì)于內(nèi)存泄露的檢測(cè),常用的工具有LeakCanary、MAT(Memory Analyer Tools)、Android Studio自帶的Profiler。關(guān)于用法,網(wǎng)上教程很多,可自行查閱。

          6、如何實(shí)現(xiàn)啟動(dòng)優(yōu)化,有什么工具可以使用?

          重點(diǎn)提到了systrace這個(gè)工具,詳細(xì)用法可以參考下面幾篇文章:
          https://blog.csdn.net/Kitty_Landon/article/details/79192377
          https://www.cnblogs.com/baiqiantao/p/7700511.html
          https://blog.csdn.net/xiyangyang8/article/details/50545707
          https://blog.csdn.net/cxq234843654/article/details/74388328

          7、常用的設(shè)計(jì)模式有哪些?是否了解責(zé)任鏈模式?

          單例模式,觀察者模式,工廠模式,建造者模式,構(gòu)造者模式,中間者模式,橋接模式,適配器模式等等。

          總結(jié)

          現(xiàn)在回顧一下,問的問題并不難,只是環(huán)環(huán)相扣問出了很多細(xì)節(jié)相關(guān)的知識(shí)點(diǎn)。由此看來,在日常開發(fā)中還需要注重基礎(chǔ)。尤其對(duì)于開發(fā)經(jīng)驗(yàn)是1-5年內(nèi)的Android Developer,面試官考察的多數(shù)是基礎(chǔ)知識(shí)是否牢固,溝通表達(dá)能力,總結(jié)能力。雖然此次面試黃了,但不失為一次很好的經(jīng)歷。

          在這里,我為大家準(zhǔn)備了一份2020年最新最全的面試題及答案,這套電子書涵蓋了諸多后端,客戶端,前端技術(shù)棧的面試題和答案,相信可以幫助大家在最短的時(shí)間內(nèi)復(fù)習(xí)的大多數(shù)面試題,從而拿到自己心儀的offer。



          —?完?—


          前線推出學(xué)習(xí)交流群一定要備注:研究/工作方向+地點(diǎn)+學(xué)校/公司+昵稱(如java+上海+上交+可可),根據(jù)格式備注,可更快被通過且邀請(qǐng)進(jìn)群

          掃碼加小編微信進(jìn)群,

          內(nèi)推和技術(shù)交流,大佬們零距離


          瀏覽 73
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91蝌蚪91 九色白浆 | 观看一级黄片 | 久久黄色精品视频 | 免费黄色视频久久 | 天天久久夜夜一起射 |