字節跳動Android面試題目與答案(2020)

一面

Java部分

Java集合

Hashmap

Hashmap和Linkedhashmap
hashmap的index算法
Hashmap的擴容?可以不是2倍嗎?爲什麼?
Hashmap的put都做了什麼
Linkedhashmap是如何保證插入有序的?如何保證數組的內容和鏈的內容都有序?

這部分問的很詳細,面試之前最好看一遍源碼,可以參考如下博客:
HashMap? ConcurrentHashMap? 相信看完這篇沒人能難住你!

多線程相關

線程池

四種線程池和創建線程池的必要參數
什麼時候創建非核心線程
核心線程會被回收麼
非核心線程什麼時候會被回收

這部分問的也比較細,主要理解四種線程池的特點,非核心線程和核心線程的區別,可以參考劉望舒的《Android進階之光》,裏面有非常詳細的描述。

wait和sleep的區別

先來看一下線程狀態圖
在這裏插入圖片描述
sleep
1、讓當前線程休眠指定時間,進入sleeping狀態
休眠時間的準確性依賴於系統時鐘和CPU調度機制。
2、不釋放已獲取的鎖資源,如果sleep方法在同步上下文中調用,那麼其他線程是無法進入到當前同步塊或者同步方法中的
3、可通過調用interrupt()方法來喚醒休眠線程。
4、sleep方法定義在java.lang.Thread中,作用於當前線程
5、sleep是靜態方法

wait
1、讓當前線程進入等待狀態,當別的其他線程調用notify()或者notifyAll()方法時,當前線程進入就緒狀態
2、wait方法必須在同步上下文中調用,例如:同步方法塊或者同步方法中,這也就意味着如果你想要調用wait方法,前提是必須獲取對象上的鎖資源
3、當wait方法調用時,當前線程將會釋放已獲取的對象鎖資源,並進入等待隊列,其他線程就可以嘗試獲取對象上的鎖資源
4、wait方法定義在Object類中,作用於對象本身;
4、wait是實例方法;

notify和notifyall的區別?爲什麼?

1)如果我使用notify(),將通知哪個線程?
無法保證,ThreadScheduler將從等待該監視器上的線程的池中選擇一個隨機線程。保證只有一個線程會被通知(隨機性);
2) 我怎麼知道有多少線程在等待,所以我可以使用notifyAll()?
它取決於程序邏輯,在編碼時需要考慮一段代碼是否可以由多個線程運行。理解線程間通信的一個很好的例子是在Java中實現生產者 - 消費者模式。
3) 如何調用notify()?
Wait()和notify()方法只能從synchronized方法或塊中調用,需要在其他線程正在等待的對象上調用notify方法。
4) 什麼是這些線程等待被通知等?
線程等待某些條件,例如在生產者 - 消費者問題中,如果共享隊列已滿,則生產者線程等待,如果共享隊列爲空,則生成者線程等待。由於多個線程正在使用共享資源,因此它們使用wait和notify方法相互通信。

鎖池
  假設線程A已經擁有對象鎖,線程B、C想要獲取鎖就會被阻塞,進入一個地方去等待鎖的等待,這個地方就是該對象的鎖池;
等待池
  假設線程A調用某個對象的wait方法,線程A就會釋放該對象鎖,同時線程A進入該對象的等待池中,進入等待池中的線程不會去競爭該對象的鎖。

notify和notifyAll的區別
1、notify只會隨機選取一個處於等待池中的線程進入鎖池去競爭獲取鎖的機會;
2、notifyAll會讓所有處於等待池的線程全部進入鎖池去競爭獲取鎖的機會;

java.util.concurrent.locks下的Condition 他可以支持喚醒指定的線程

synchornized作用在靜態方法和普通方法的區別,class和this的區別?

synchronized 關鍵字可以在多線程環境下用來作爲線程安全的同步鎖。
造成線程安全問題的主要誘因有兩點,一是存在共享數據(也稱臨界資源),二是存在多條線程共同操作共享數據。
因此,引入了互斥鎖的概念,即一個共享數據只能被一個線程訪問,其他線程需要等待(阻塞),直至當前線程處理完畢釋放該鎖。
所以,synchronized方法就保證了同一時刻只有一個線程對方法或者代碼塊有共享數據的操作。而且,synchronized保證了一個線程對共享變量操作的變化被其他線程看到(可以替代volatile功能)。

Synchronized就是內置鎖,是java語言特性提供的內置鎖,其獲得鎖和釋放鎖是隱式的(進入代碼塊就是獲得鎖,走出代碼就是釋放鎖)。
java.util.concurrent.locks 包中的鎖是顯示鎖,需要進行lock和unlock。

分類
1、對象鎖(對象鎖是用於對象實例方法,或者一個對象實例上的)
2、類鎖(類鎖是用於類的靜態方法或者一個類的class對象上的)
類的對象實例可以有很多個,但是每個類只有一個class對象,所以不同對象實例的對象鎖是互不干擾的,但是每個類只有一個類鎖。但是有一點必須注意的是,其實類鎖只是一個概念上的東西,並不是真實存在的,它只是用來幫助我們理解鎖定實例方法和靜態方法的區別的。

用法
1、非靜態方法的同步;(對象鎖)
2、靜態方法的同步;(類鎖)
3、代碼塊;(this則是對象鎖,A.class則是類鎖)

對象鎖
非靜態方法使用 synchronized 修飾的寫法,修飾實例方法時,鎖定的是當前對象;
代碼塊使用 synchronized 修飾的寫法,使用代碼塊,如果傳入的參數是 this,那麼鎖定的也是當前的對象;
某個線程得到了對象鎖之後,該對象的其他同步方法是鎖定的,其他線程是無法訪問的;
如果某個線程得到了對象鎖,但是另一個線程還是可以訪問沒有進行同步的方法或者代碼。進行了同步的方法(加鎖方法)和沒有進行同步的方法(普通方法)是互不影響的,一個線程進入了同步方法,得到了對象鎖,其他線程還是可以訪問那些沒有同步的方法(普通方法)。當獲取到與對象關聯的內置鎖時,並不能阻止其他線程訪問該對象,當某個線程獲得對象的鎖之後,只能阻止其他線程獲得同一個鎖。

類鎖
類鎖需要 synchronized 來修飾靜態 static 方法;
或者使用代碼塊,需引用當前的類;
由於靜態方法是類所有對象共用的,所以進行同步後,該靜態方法的鎖也是所有對象唯一的,每次只能有一個線程來訪問對象的該非靜態同步方法;
類鎖和對象鎖是不一樣的鎖,是互相獨立的

synchornized的monitor原理?

synchronized是可重入鎖
當線程請求一個由其它線程持有的對象鎖時,該線程會阻塞,而當線程請求由自己持有的對象鎖時,如果該鎖是重入鎖,請求就會成功,否則阻塞;
特別注意另外一種情況,當子類繼承父類時,子類也是可以通過可重入鎖調用父類的同步方法;
與多線程併發執行的線程安全不同,可重入強調對單個線程執行時重新進入同一個子程序仍然是安全的;

重入鎖實現可重入性原理或機制是:每一個鎖關聯一個線程持有者和計數器,當計數器爲 0 時表示該鎖沒有被任何線程持有,那麼任何線程都可能獲得該鎖而調用相應的方法;當某一線程請求成功後,JVM會記下鎖的持有線程,並且將計數器置爲 1;此時其它線程請求該鎖,則必須等待;而該持有鎖的線程如果再次請求這個鎖,就可以再次拿到這個鎖,同時計數器會遞增;當線程退出同步代碼塊時,計數器會遞減,如果計數器爲 0,則釋放該鎖。

valitile有什麼作用?是怎麼實現的?

valitile保障了有序性和可見性,不保證原子性
在多線程併發編程中synchronized和Volatile都扮演着重要的角色,Volatile是 輕量級的synchronized (它比synchronized的 使用和執行成本會更低 ,因爲它不會引起線程上下文的切換和調度),它在多處理器開發中保證了共享變量的“可見性”。可見性的意思是當一個線程修改一個共享變量時,另外一個線程能讀到這個修改的值。
有序性是指valitile禁止指令重排序;

共享變量:在多個線程之間能夠被共享的變量被稱爲共享變量。共享變量包括所有的實例變量靜態變量數組元素。他們都被存放在堆內存中,Volatile只作用於共享變量

valitile作用
1 保證變量在各個線程的可見性,意思就是說這個變量的值一修改,其他線程可以立即得知。而一個普通變量需要先寫回主內存,然後其他線程去讀取這個值。2:禁止指令重排序優化。然而它並不能保證原子性,以及運算的線程安全

valitile原理
使用Violatile修飾的變量在彙編階段,會多出一條lock前綴指令,它在多核處理器下回引發兩件事情:
1、將當前處理器緩存行的數據寫回到系統內存;
2、這個寫回內存的操作會使在其他CPU裏緩存了該內存地址的數據無效;
通常處理器和內存之間都有幾級緩存來提高處理速度,處理器先將內存中的數據讀取到內部緩存後再進行操作,但是對於緩存寫會內存的時機則無法得知,因此在一個處理器裏修改的變量值,不一定能及時寫回緩存,這種變量修改對其他處理器變得“不可見”了。
但是,使用Volatile修飾的變量,在寫操作的時候,會強制將這個變量所在緩存行的數據寫回到內存中,但即使寫回到內存,其他處理器也有可能使用內部的緩存數據,從而導致變量不一致,所以,在多處理器下,爲了保證各個處理器的緩存是一致的,就會實現緩存一致性協議,每個處理器通過嗅探在總線上傳播的數據來檢查自己緩存的值是不是過期,如果過期,就會將該緩存行設置成無效狀態,下次要使用就會重新從內存中讀取。

內存模型

Java內存模型簡單介紹下?堆區域都保存什麼?棧區域都保存什麼?方法區都保存什麼?

深入理解Java內存模型
JVM內存模型

簡述GC回收機制?什麼適合做引用鏈的根結點?(常量和棧中內容)

GC垃圾回收機制詳解

基本不做回收的區域
Java運行時內存區域中,程序計數器、虛擬機棧、本地方法棧這3個區域基本不會被GC。因爲這3個區域隨線程而生,隨線程而亡,棧中棧幀分配對少內存在類結構確定下來的時候就已知了(大體編譯期佔用多少內存已知),因此這幾個區域的內存分配和回收具備確定性。

回收區域
Java堆和方法區。這部分區域對象在運行時才知道要分配什麼對象,分配多少對象,分配多大對象,因此這部分的分配和回收是動態的。

內部類

靜態內部類和非靜態內部類區別?

Java內部類詳解

內部類
內部類就是定義在一個類的內部,包含內部類的類就稱爲外部類
第一,內部類可以訪問其所在類的屬性(包括所在類的私有屬性),內部類創建自身對象需要先創建其所在類的對象
第二,可以定義內部接口,且可以定義另外一個內部類實現這個內部接口;
第三,可以在方法體內定義一個內部類,方法體內的內部類可以完成一個基於虛方法形式的回調操作;
第四,內部類不能定義static元素;(靜態的內部類可以)
第五,內部類可以多嵌套;

static內部類是內部類中一個比較特殊的情況,Java文檔中是這樣描述static內部類的:一旦內部類使用static修飾,那麼此時這個內部類就升級爲頂級類。
也就是說,除了寫在一個類的內部以外,static內部類具備所有外部類的特性;

static內部類不僅可以在內部定義static元素,而且在構建對象的時候也可以一次完成。從某種意義上說,static內部類已經不算是嚴格意義上的內部類了。

與static內部類不同,內部接口自動具備靜態屬性,也就是說,普通類是可以直接實現內部接口的;

引用

強引用 軟引用 弱引用 虛引用

一,強引用
Java中默認聲明的就是強引用,只要強引用存在,垃圾回收器將永遠不會回收被引用的對象,哪怕內存不足時,JVM也會直接拋出OutOfMemoryError,不會去回收。如果想中斷強引用與對象之間的聯繫,可以顯示的將強引用賦值爲null,這樣一來,JVM就可以適時的回收對象了;

二,軟引用
軟引用是用來描述一些非必需但仍有用的對象。在內存足夠的時候,軟引用對象不會被回收,只有在內存不足時,系統則會回收軟引用對象,如果回收了軟引用對象之後仍然沒有足夠的內存,纔會拋出內存溢出異常。這種特性常常被用來實現緩存技術,比如網頁緩存,圖片緩存等。

三,弱引用
弱引用的引用強度比軟引用要更弱一些,無論內存是否足夠,只要 JVM 開始進行垃圾回收,那些被弱引用關聯的對象都會被回收。

四,虛引用
虛引用是最弱的一種引用關係,如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,它隨時可能會被回收,

網絡協議

TCP和UDP

什麼情況下用UDP?什麼情況下用UDP?舉個例子
TCP爲什麼比UDP效率低?(超時重傳機制,,還有一個是啥?記不清了。。。)

HTTPS

簡述HTTPS?
爲什麼第一步要是用非對稱加密?
CA證書都包含哪些信息?
爲什麼HTTPS要是用對稱加密技術?
說說你對session和cookie的理解?
session服務器端是怎麼管理的?
multipleForm是什麼?有什麼作用?(上傳文件同時附加信息,還有啥??)

Android部分

Android動畫

Android中提供的三種動畫,有什麼區別?

異步操作

android中的異步操作

安卓異步任務處理

intentservice和service

handlerthread和thread

looper原理

threadlocal在looper中的作用
handler導致內存泄漏除了remove還怎麼解決?

Android Handler總結一:Handler使用
Android Handler總結二:HandlerThread
Android Handler總結三:源碼分析

持久化

文件存儲形式?ContentProvider何時創建?SP線程安全嗎?

android 五種數據存儲 :SharePreferences、SQLite、Contert Provider、File、網絡存儲

Android系統提供了四種存儲數據方式。分別爲:SharePreference、SQLite、Content Provider和File。但由於Android系統中,數據基本是私有的,都是存放於”data/data”程序包名目錄下,所以要實現數據共享,正確方式是使用Content Provider

SQLite:SQLite是一個輕量級的數據庫,支持基本的SQL語法,是常被採用的一種數據存儲方式。Android爲此數據庫提供了一個名爲SQLiteDatabase的類,封裝了一些操作數據庫的api

SharedPreference: 除SQLite數據庫外,另一種常用的數據存儲方式,其本質就是一個xml文件,常用於存儲較簡單的參數設置。

File: 即常說的文件(I/O)存儲方法,常用語存儲大數量的數據,但是缺點是更新數據將是一件困難的事情。

ContentProvider: Android系統中能實現所有應用程序共享的一種數據存儲方式,由於數據通常在各應用間的是互相私密的,所以此存儲方式較少使用,但是其又是必不可少的一種存儲方式。例如音頻,視頻,圖片和通訊錄,一般都可以採用此種方式進行存儲。每個Content Provider都會對外提供一個公共的URI(包裝成Uri對象),如果應用程序有數據需要共享時,就需要使用Content Provider爲這些數據定義一個URI,然後其他的應用程序就通過Content Provider傳入這個URI來對數據進行操作。

URI由3個部分組成:“content://”、數據的路徑、標識ID(可選)。

Sp實現原理和如何實現線程安全

算法部分

1、環形打印二維數組
2、約瑟夫問題(兩種實現方式,一種鏈表,一種數組)
3、兩個棧實現隊列的pop和push;
4、單鏈表的初始化,返回第一個節點;返回倒數第N個節點

二面

算法

實現鏈表數字的加法與輸出

你是怎麼理解內部類的?

手寫如何創建非靜態內部類對象的創建與靜態內部類的創建

你是怎麼理解註解的?

Java註解總結

Java註解精講

你是如何理解Service的?和線程的區別?

IntentService和Service的區別?線程是串行的還是並行的?
Service怎麼啓動?兩種方式有什麼區別?

Android組件之Service理解

你對View事件分發是如何理解的?

一個View消費了DOWN事件,後面的MOVE、UP事件還會攔截嗎?
DOWN、UP事件詳解

簡述你對HTTP協議的理解?

HTTPS加密機制解析與總結

HTTPS協議格式是什麼樣的?
有哪些方法(GET,POST,PUT、DELETE…要全部說出來)?
不同方法中有什麼區別?
都有哪些響應?

301和303的區別?
403和404的區別?
Http教程

簡述你對HyBrid的理解?

JSBridge的原理?代碼是怎麼注入的?
回調和異步如何實現?
你怎麼認識WebClient和WebChromeClient?

Android HyBrid開發實戰

JSBridge實現原理
1、在Native端編寫本地功能的Java類(如HostJsScope.java);
2、在初始化WebviewChromeClient時根據該類反射動態生成JS代碼;
3、將動態生成的JS代碼通過WebView.loadUrl觸發的onProgressChanged方法注入到webview中,供前端可調用。注意這裏註冊的不是Java對象了,而是js對象,而且這個對象過濾掉了Object的公有方法,所以是安全的,同時是在onProgressChanged方法中將js代碼注入,
經過我的測試,在WebviewChromeClient的這個回調中注入js代碼可以長期保留,不會因跳轉到下一個頁面而無效。
4、在前端調用HostJsScope對應的接口,觸發webview的onPrompt事件,進而調用本地Java方法,如果有返回值則調用JsCallback將數據返回前端;

Web中有些資源放在App資源目錄下,如何實現?
web img加載Android本地圖片

App的網絡cookie和Web的Cookie如何同步?
Android H5 cookie同步

Android 中的cookie介紹

簡述你對px,dp,dip的認識?

總結

宇宙條果然不是吹的,對技術的要求很高。
一面問的特別詳細,問的時間特別長,主要是Java基本功的考察,問的也比較深入;
二面主要考察你對Android開發各方面的理解和總結,比較寬泛,儘量以點帶面,展開來說;

關於算法,要求也比較高,一面二面都需要手寫算法,而且定時,一般五分鐘之內;這塊也需要練下下。

附加題目

1、兩個算法;
2、java四中修飾符;
3、二叉樹、排序二叉樹、平衡二叉樹、紅黑樹;
4、hashmap原理,hashmap和hashtable的區別;
5、wait和sleep的區別;
6、valitle關鍵字作用;
7、雙親委派模型;
8、service兩種啓動模式的區別;bind方式一定會stopservice嗎?先start後bind生命週期是什麼樣?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章