致那些面試中的辛酸坎坷史.....
一、騰訊
面試時(shí)間:2019.12.18
面試部門:QQ 瀏覽器
你是如何來優(yōu)化業(yè)務(wù) RN 頁面的性能的?
在治理 RN 頁面的 JS 錯(cuò)誤時(shí),你的方案是什么,如何設(shè)計(jì)的方案?
MRN 比 原生 RN,有什么功能優(yōu)勢?
MRN 頁面你們關(guān)注的性能指標(biāo)有哪些?為什么要關(guān)注這些指標(biāo)?
構(gòu)造一個(gè)出現(xiàn)死鎖的情況
實(shí)現(xiàn)一個(gè)線程同步的計(jì)數(shù)器
synchronized 底層實(shí)現(xiàn)
說兩個(gè)線程同步的集合類
進(jìn)程間通信的方式有哪些?
Activity 與 Service 的區(qū)別?Service 一定沒界面嗎,Activity 一定有界面嗎?
- Activity 不是一定有界面。比如一個(gè)跳轉(zhuǎn)邏輯控制類(機(jī)票的支付中間類)、透明頁
- Service 也不是一定沒界面。Service 并不依賴于用戶可視的 UI 界面,但這也不是絕對的,如前臺(tái) Service 就是與 Notification 界面結(jié)合使用的;Service 中也可以彈 Toast;
- Service中執(zhí)行 LayoutInflate 是合法的,但是會(huì)使用系統(tǒng)默認(rèn)的主題樣式,如果你自定義了某些樣式可能不會(huì)被使用。所以從理論上看也是可以有界面的
- Activity 按 back 鍵退出,與強(qiáng)殺進(jìn)程退出有啥區(qū)別?
(1)應(yīng)用被強(qiáng)殺
- 整個(gè)App進(jìn)程都被殺掉了,所有變量全都被清空,包括Application實(shí)例,更別提靜態(tài)變量;
- 雖然變量被清空了,但 Activity 棧沒有被清空,也就是說 A -> B -> C 這個(gè)棧還保存了,只是ABC 這幾個(gè) Activity 實(shí)例沒有了。所以回到 App 時(shí),顯示的還是 C 頁面。另外當(dāng) Activity 被強(qiáng)殺時(shí),系統(tǒng)會(huì)調(diào)用 onSaveInstance 去讓你保存一些變量;
- 當(dāng)應(yīng)用回到前臺(tái)時(shí),如果C頁面中有靜態(tài)變量或有些Application的全局變量,就NullPointer了;
- C頁面不會(huì)正常走完生命周期onStop & onDestory
(2)按 Back 鍵回退
- 應(yīng)用進(jìn)程不會(huì)被殺掉;Activity 棧由 A -> B -> C 變成 A -> B;
- C頁面會(huì)正常走完生命周期onStop & onDestory
構(gòu)造一個(gè)內(nèi)存泄露的場景
Android 虛擬機(jī)有哪些?區(qū)別是什么?
如何做屏幕適配,是否對小屏手機(jī)有專門的適配?
(1)Android 目前穩(wěn)定高效的UI適配方案、今日頭條屏幕適配方案 AndroidAutoSize:
- dpi:屏幕像素密度,指的是在系統(tǒng)軟件上指定的單位尺寸的像素?cái)?shù)量,它往往是寫在系統(tǒng)出廠配置文件的一個(gè)固定值;
- ppi:也是屏幕像素密度,但這個(gè)是物理上的概念,它是客觀存在的不會(huì)改變。dpi是軟件參考了物理像素密度后,人為指定的一個(gè)值,這樣保證了某一個(gè)區(qū)間內(nèi)的物理像素密度在軟件上都使用同一個(gè)值
- dp加上自適應(yīng)布局和weight比例布局能解決90%的適配問題。因?yàn)椴⒉皇撬械?080P的手機(jī)dpi都是480,比如Google 的Pixel2(1920*1080)的dpi是420
- 寬高限定符適配:窮舉市面上所有的Android手機(jī)的寬高像素值,設(shè)定一個(gè)基準(zhǔn)的分辨率,其他分辨率都根據(jù)這個(gè)基準(zhǔn)分辨率來計(jì)算,在不同的尺寸文件夾內(nèi)部,根據(jù)該尺寸編寫對應(yīng)的dimens文件。但其有一個(gè)致命的缺陷,那就是需要精準(zhǔn)命中才能適配,App包體積也會(huì)變大
Java中中文字符和英文字符的大小分別多少?在網(wǎng)絡(luò)上傳輸大小又分別是多少?
Java GC機(jī)制,為什么要執(zhí)行 GC
那些不可能再被任何途徑使用的對象,需要被回收,否則內(nèi)存遲早都會(huì)被消耗空
平時(shí)開發(fā)中你是怎么保證質(zhì)量的,團(tuán)隊(duì)項(xiàng)目的質(zhì)量又是如何保證的?
如何使用 git 來協(xié)作團(tuán)隊(duì)開發(fā)流程的
項(xiàng)目 A 依賴 項(xiàng)目B,項(xiàng)目 B 依賴項(xiàng)目 C,項(xiàng)目C又依賴項(xiàng)目 A,這樣會(huì)有問題嗎?
上面的問題,給出有問題或沒問題的原因,怎么解決?
說一個(gè)你覺得讓你成長很大,或者印象比較深刻的項(xiàng)目
給你一個(gè)開發(fā)項(xiàng)目,如何管理,怎么制定開發(fā)規(guī)范
你覺得你相對其他的人的優(yōu)勢是什么,劣勢是什么?
假設(shè)現(xiàn)在給你一個(gè)很有挑戰(zhàn)的難題去攻關(guān),你會(huì)樂意去做嗎?
附:三個(gè)面過的騰訊算法題
- 求一個(gè)整數(shù)的二進(jìn)制中 1 的個(gè)數(shù)
- 不知道頭結(jié)點(diǎn)的鏈表,刪除指定結(jié)點(diǎn)
- 字符串找首位最大重復(fù)子串
二、快手
面試時(shí)間:2019.12.19
面試部門:商業(yè)化
- hashcode 與 equal 區(qū)別?
(1)關(guān)系操作符 ==
- 若操作數(shù)的類型是基本數(shù)據(jù)類型,則該關(guān)系操作符判斷的是左右兩邊操作數(shù)的值是否相等
- 若操作數(shù)的類型是引用數(shù)據(jù)類型,則該關(guān)系操作符判斷的是左右兩邊操作數(shù)的內(nèi)存地址是否相同。也就是說,若此時(shí)返回 true, 則該操作符作用的一定是同一個(gè)對象
(2)equals(內(nèi)部實(shí)現(xiàn)三個(gè)步驟)
- 先 比較引用是否相同 (是否為同一對象)
- 再 判斷類型是否一致(是否為同一類型)
- 最后 比較內(nèi)容是否一致
- 注:equal 的默認(rèn)行為是比較引用,所以除非在自己的新類中覆蓋了 equal() 方法,否則不可能表現(xiàn)出我們希望的行為
(3)hashCode
- hashcode 是系統(tǒng)用來快速檢索對象而使用(一般在需要用哈希算法的數(shù)據(jù)結(jié)構(gòu)中才有用,比如 HashSet, HashMap 和 Hashtable)
- 重寫 equals 方法和 hashcode 方法時(shí),equals 方法中用到的成員變量也必定會(huì)在 hashcode 方法中用到,只不過前者作為比較項(xiàng),后者作為生成摘要的信息項(xiàng),本質(zhì)上所用到的數(shù)據(jù)是一樣的,從而保證二者的一致性
(4)equals 與 hashCode 關(guān)系
- 如果兩個(gè)對象 equals,那么它們的 hashCode 必然相等
- 但是 hashCode 相等,equals 不一定相等
hashmap 實(shí)現(xiàn)原理,給一個(gè) key 如何計(jì)算槽位,如何取值?
如何做的 RN 頁面的性能優(yōu)化
Flutter 有了解過沒有?與 RN 的區(qū)別是什么
RN 與 Native 的對比
造成 oom 的原因
說一些引起內(nèi)存泄漏的場景
內(nèi)存泄漏怎么來檢測,LeakCanary 的原理是什么
檢測到內(nèi)存泄漏怎么修復(fù)
service 的 bindservice() 與 startService 區(qū)別
requestLayout,invalidate 的區(qū)別
下面代碼是否能編譯通過:
Number[] a = new Integer[] {0}; // 能通過
List<Number> a = new ArrayList<Integer> (); // 不能通過
Serializable 與 Parcelable 的區(qū)別?
Serializable 中的 serialVersionUID 作用,如果修改了一個(gè)值,這個(gè)ID是否會(huì)改變?
Android Touch 事件的分發(fā)機(jī)制
橫向 ScrollView、縱向 ListView 怎么處理滑動(dòng)手勢沖突
數(shù)據(jù)結(jié)構(gòu)-二叉樹的廣度遍歷
其他若干項(xiàng)目相關(guān)問題
三、美團(tuán)外賣
面試時(shí)間:2019.12.25
面試部門:外賣商家端
面試情況:已通過
- Java 虛擬機(jī)類加載器分類,類加載器的代理機(jī)制有什么好處?
(1)類加載器分類
- 啟動(dòng)類加載器:加載 Java 的核心庫,是用原生代碼來實(shí)現(xiàn)的,并不繼承自 java.lang.ClassLoader;
- 擴(kuò)展類加載器:加載 Java 的擴(kuò)展庫。Java 虛擬機(jī)的實(shí)現(xiàn)會(huì)提供一個(gè)擴(kuò)展庫目錄。該類加載器在此目錄里面查找并加載 Java 類;
- 系統(tǒng)/應(yīng)用類加載器:它根據(jù) Java 應(yīng)用的類路徑(CLASSPATH)來加載 Java 類。一般來說,Java 應(yīng)用的類都是由它來完成加載的??梢酝ㄟ^ ClassLoader.getSystemClassLoader()來獲取它;
- 注:類加載器樹狀組織結(jié)構(gòu),除了引導(dǎo)類加載器之外,所有的類加載器都有一個(gè)父類加載器。類加載器 Java 類如同其它的 Java 類一樣,也是要由類加載器來加載的。
(2)類加載器的代理機(jī)制
- 原理:類加載器在嘗試自己去查找某個(gè)類的字節(jié)代碼并定義它時(shí),會(huì)先代理給其父類加載器,由父類加載器先去嘗試加載這個(gè)類,依次類推;
- 作用:代理模式是為了保證 Java 核心庫的類型安全。對于Java 核心庫的類的加載工作由引導(dǎo)類加載器來統(tǒng)一完成,保證了 Java 應(yīng)用所使用的都是同一個(gè)版本的 Java 核心庫的類,是互相兼容的。
傳送門:深入探討 Java 類加載器
- Java 虛擬機(jī)是如何判定兩個(gè) Java 類是相同的?
- Java 虛擬機(jī)不僅要看類的全名是否相同,還要看加載此類的類加載器 (defining loader) 是否一樣。即便是同樣的字節(jié)代碼,被不同的類加載器加載之后所得到的類,也是不同的;
- 不同的類加載器為相同名稱的類創(chuàng)建了額外的名稱空間。相同名稱的類可以并存在 Java 虛擬機(jī)中,只需要用不同的類加載器來加載它們即可。不同類加載器加載的類之間是不兼容的,這就相當(dāng)于在 Java 虛擬機(jī)內(nèi)部創(chuàng)建了一個(gè)個(gè)相互隔離的 Java 類空間。
- Java 類的加載過程是什么?
Java 類的加載過程 - 三個(gè)主要步驟:加載、鏈接、初始化:
(1)加載 - 將字節(jié)碼數(shù)據(jù)從不同的數(shù)據(jù)源讀取到 JVM 中,并映射為 JVM 認(rèn)可的數(shù)據(jù)結(jié)構(gòu) (Class 對象)
- 由于類加載器的代理機(jī)制,啟動(dòng)類加載過程的類加載器和真正完成類加載工作的類加載器,有可能不同;
- 啟動(dòng)類的加載過程通過調(diào)用loadClass()來實(shí)現(xiàn),稱為初始加載器 (initiating loader);而完成類的加載工作通過調(diào)用defineClass()來實(shí)現(xiàn),稱為類的定義加載器 (defining loader)。在 Java 虛擬機(jī)判斷兩個(gè)類是否相同的時(shí)候,使用的是類的定義加載器;
- loadClass() 拋出的是 java.lang.ClassNotFoundException 異常,而 defineClass() 拋出的是 java.lang.NoClassDefFoundError 異常;
- 類加載器在成功加載某個(gè)類之后,會(huì)把得到的 java.lang.Class 類的實(shí)例緩存起來。下次再請求加載該類的時(shí)候,類加載器會(huì)直接使用緩存的類的實(shí)例,而不會(huì)嘗試再次加載 (即 loadClass()不會(huì)被重復(fù)調(diào)用)
(2)鏈接 - 將原始的類定義信息平滑地轉(zhuǎn)化入 JVM 運(yùn)行的過程中
- 驗(yàn)證:核驗(yàn)字節(jié)信息是符合 Java 虛擬機(jī)規(guī)范;
- 準(zhǔn)備:創(chuàng)建類或接口中的靜態(tài)變量并初始化,側(cè)重分配所需要的內(nèi)存空間(與初始化階段區(qū)分開);
- 解析:替換常量池中的符號(hào)引用為直接引用,類、接口、方法和字段等各個(gè)方面的解析等
(3)初始化 - 真正執(zhí)行類初始化的代碼邏輯,包括靜態(tài)字段賦值的動(dòng)作,以及類中靜態(tài)初始化塊內(nèi)的邏輯。編譯器在編譯階段就會(huì)把這部分邏輯整理好,父類型的初始化邏輯優(yōu)先于當(dāng)前類型的邏輯
Java 中的幾種引用類型,虛引用的使用場景?
Java GC 的幾種算法
Java GC 是如何判斷對象是可以被回收的?
- 自動(dòng)垃圾收集的前提是清楚哪些內(nèi)存可以被釋放,主要有兩個(gè)方面,最主要部分就是對象實(shí)例,存儲(chǔ)在堆上的;另一個(gè)是方法區(qū)中的元數(shù)據(jù)等信息,例如類型不再使用,卸載該 Java 類比較合理;
- 對象實(shí)例收集主要是兩種基本算法,引用計(jì)數(shù)和可達(dá)性分析,Java 選擇的可達(dá)性分析。JVM 會(huì)把虛擬機(jī)棧和本地方法棧中正在引用的對象、靜態(tài)屬性引用的對象和常量**,作為 GC Roots。
- synchronized 的 4 種狀態(tài)
- 不可不說的Java“鎖”事
- 訪問 synchronized 修飾static方法、synchronized(this|object) 是否會(huì)沖突受干擾
- 訪問 synchronized 修飾 static 方法、synchronized (類.class) 是否會(huì)沖突受干擾
- okhttp 在 response 返回后,調(diào)用了 response.toString(),后面再使用 response 會(huì)用什么問題?
調(diào)用 response.toString() 連接會(huì)斷開,后面的取值會(huì)出問題!魔性的問題...
Handler 空閑會(huì)不會(huì)阻塞主線程,IdleHandler 使用場景
LeakCanary 的收集內(nèi)存泄露是在 Activity 的什么時(shí)機(jī),大致原理
如何修復(fù)匿名內(nèi)部類 handler 造成的內(nèi)存泄露?
Handler 機(jī)制中是怎么保證每個(gè)線程的 Looper 是唯一的?
泛型擦除發(fā)生的時(shí)機(jī)是什么時(shí)候?
在編譯期。我眼中的Java-Type體系
MRN 單工程多 bundle,單工程單 bundle 的優(yōu)缺點(diǎn)對比
MRN 長列表的性能問題,頁面白屏
介紹下 Redux 的工作原理
創(chuàng)建線程池的幾個(gè)關(guān)鍵參數(shù)(核心線程、最大線程....)
Retrofit 的實(shí)現(xiàn)原理,使用了什么的設(shè)計(jì)模式?優(yōu)勢是什么?
Gradle 的工作原理
RN中,JS 與 Native 是怎么通信的?
MRN 的初始化過程?如何加載 NativeModule 的?
MRN 的頁面(也就是bundle)緩存機(jī)制
對于 MRN,你們是怎么處理 JNI 異常的?
其他項(xiàng)目相關(guān)問題
文中若有不對的地方,歡迎大家批評斧正,謝謝~