安卓面試題整理2020

面試總是碰到各種難題,相信很多碼農(nóng)跟我一樣總是重復(fù)于業(yè)務(wù)層的開發(fā),對底層的了解完全是因?yàn)槊嬖囆枰?,這里將部分面試題進(jìn)行整理,可以方便學(xué)習(xí),希望也能方便工友們一起學(xué)習(xí)。

基礎(chǔ)部分:

1、內(nèi)存泄漏:

? ??????內(nèi)存泄露的根本原因:長生命周期的對象持有短生命周期的對象。短周期對象就無法及時釋放。

1.靜態(tài)集合類引起內(nèi)存泄露

主要是hashmap,Vector等,如果是靜態(tài)集合 這些集合沒有及時setnull的話,就會一直持有這些對象。

2.remove 方法無法刪除set集 Objects.hash(firstName, lastName);

經(jīng)過測試,hashcode修改后,就沒有辦法remove了。

3.observer 我們在使用監(jiān)聽器的時候,往往是addxxxlistener,但是當(dāng)我們不需要的時候,忘記removexxxlistener,就容易內(nèi)存leak。

廣播沒有unregisterrecevier

4.各種數(shù)據(jù)鏈接沒有關(guān)閉,數(shù)據(jù)庫contentprovider,io,sokect等。cursor

5.內(nèi)部類:

java中的內(nèi)部類(匿名內(nèi)部類),會持有宿主類的強(qiáng)引用this。

所以如果是new Thread這種,后臺線程的操作,當(dāng)線程沒有執(zhí)行結(jié)束時,activity不會被回收。

Context的引用,當(dāng)TextView 等等都會持有上下文的引用。如果有static drawable,就會導(dǎo)致該內(nèi)存無法釋放。

6.單例

單例 是一個全局的靜態(tài)對象,當(dāng)持有某個復(fù)制的類A是,A無法被釋放,內(nèi)存leak。

2、內(nèi)存溢出

當(dāng)程序需要申請一段“大”內(nèi)存,但是虛擬機(jī)沒有辦法及時的給到,即使做了GC操作以后

這就會拋出 OutOfMemoryException 也就是OOM。避免如下:

1、減少內(nèi)存對象的占用,比如

ArrayMap/SparseArray代替hashmap

避免在android里面使用Enum

減少bitmap的內(nèi)存占用

inSampleSize:縮放比例,在把圖片載入內(nèi)存之前,我們需要先計(jì)算出一個合適的縮放比例,避免不必要的大圖載入。

decode format:解碼格式,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差異。

減少資源圖片的大小,過大的圖片可以考慮分段加載

2、內(nèi)存對象的重復(fù)利用

大多數(shù)對象的復(fù)用,都是利用對象池的技術(shù)。

listview/gridview/recycleview contentview的復(fù)用

inBitmap 屬性對于內(nèi)存對象的復(fù)用ARGB_8888/RBG_565/ARGB_4444/ALPHA_8

這個方法在某些條件下非常有用,比如要加載上千張圖片的時候。

避免在ondraw方法里面 new對象

StringBuilder 代替+

3、ANR 是什么?怎樣避免和解決 ANR

ANR->Application Not Responding

也就是在規(guī)定的時間內(nèi),沒有響應(yīng)。

三種類型:

1). KeyDispatchTimeout(5 seconds) —主要類型按鍵或觸摸事件在特定時間內(nèi)無響應(yīng)

2). BroadcastTimeout(10 seconds) —BroadcastReceiver在特定時間內(nèi)無法處理完成

3). ServiceTimeout(20 seconds) —小概率類型 Service在特定的時間內(nèi)無法處理完成

為什么會超時:事件沒有機(jī)會處理 & 事件處理超時

怎么避免ANR

ANR的關(guān)鍵

是處理超時,所以應(yīng)該避免在UI線程,BroadcastReceiver 還有service主線程中,處理復(fù)雜的邏輯和計(jì)算

而交給work thread操作。

1)避免在activity里面做耗時操作,oncreate & onresume

2)避免在onReceiver里面做過多操作

3)避免在Intent Receiver里啟動一個Activity,因?yàn)樗鼤?chuàng)建一個新的畫面,并從當(dāng)前用戶正在運(yùn)行的程序上搶奪焦點(diǎn)。

4)盡量使用handler來處理UI thread & workthread的交互。

如何解決ANR

首先定位ANR發(fā)生的log:

04-0113:12:11.572I/InputDispatcher(220):Applicationisnot responding:Window{2b263310com.android.email/com.android.email.activity.SplitScreenActivitypaused=false}.5009.8ms sinceevent,5009.5ms since waitstartedCPUusagefrom4361ms to699ms ago----CPU在ANR發(fā)生前的使用情況04-0113:12:15.872E/ActivityManager(220):100%TOTAL:4.8%user+7.6%kernel+87%iowait04-0113:12:15.872E/ActivityManager(220):CPUusagefrom3697ms to4223ms later:--ANR后CPU的使用量

從log可以看出,cpu在做大量的io操作。

所以可以查看io操作的地方。

當(dāng)然,也有可能cpu占用不高,那就是 主線程被block住了。

4、.Framework 工作方式及原理,Activity 是如何生成一個 view 的,機(jī)制是什么

Framework是android 系統(tǒng)對 linux kernel,lib庫等封裝,提供WMS,AMS,bind機(jī)制,handler-message機(jī)制等方式,供app使用。

簡單來說framework就是提供app生存的環(huán)境。

1)Activity在attch方法的時候,會創(chuàng)建一個phonewindow(window的子類)

2)onCreate中的setContentView方法,會創(chuàng)建DecorView

3)DecorView 的addview方法,會把layout中的布局加載進(jìn)來。

5、橫豎屏切換問題

關(guān)于Android橫豎屏切換Activity是否會銷毀重建,這個由Activity的configChanges屬性控制。當(dāng)一個配置改變時Activity默認(rèn)會銷毀重建,但是如果這個屬性聲明了此項(xiàng)配置后,Activit就不會銷毀重建,而是回調(diào)Activity的onConfigurationChanged方法。

橫豎屏切換 - Activity銷毀重建

對于android3.2(API13)及以后的系統(tǒng),以下任意一種配置,橫豎屏切換Activity的生命周期都會重新執(zhí)行一次:

1.不配置configChanges屬性

2.設(shè)置android:configChanges="orientation"

3.設(shè)置android:configChanges="orientation|keyboardHidden"(3.2系統(tǒng)之前的系統(tǒng)不會執(zhí)行生命周期方法了)

配置android:configChanges="orientation|keyboardHidden|screenSize"可以控制Activity在橫豎屏切換時不銷毀重建

6、websocket 和socket區(qū)別

Socket是傳輸控制層協(xié)議,WebSocket是應(yīng)用層協(xié)議。Socket其實(shí)并不是一個協(xié)議,而是為了方便使用TCP或UDP而抽象出來的一層,是位于應(yīng)用層和傳輸控制層之間的一組接口。當(dāng)兩臺主機(jī)通信時,必須通過Socket連接,Socket則利用TCP/IP協(xié)議建立TCP連接。TCP連接則更依靠于底層的IP協(xié)議,IP協(xié)議的連接則依賴于鏈路層等更低層次。WebSocket同HTTP一樣是應(yīng)用層的協(xié)議,但是它是一種雙向通信協(xié)議,是建立在TCP之上的。websocket通信過程如下:

1. 瀏覽器、服務(wù)器建立TCP連接,三次握手。這是通信的基礎(chǔ),傳輸控制層,若失敗后續(xù)都不執(zhí)行。

2. TCP連接成功后,瀏覽器通過HTTP協(xié)議向服務(wù)器傳送WebSocket支持的版本號等信息。(開始前的HTTP握手)

3. 服務(wù)器收到客戶端的握手請求后,同樣采用HTTP協(xié)議回饋數(shù)據(jù)。

4. 當(dāng)收到了連接成功的消息后,通過TCP通道進(jìn)行傳輸通信。


底層原理:

1、虛擬機(jī)內(nèi)存模型


JVM內(nèi)存模型

JVM(Java Virtual Machine)的內(nèi)存空間分為5部分:

(1)PC Register 程序計(jì)數(shù)器

(2)JVM Stack java虛擬機(jī)棧

(3)Native Method Stack 本地方法棧

(4)Head 堆

(5)Method Area 方法區(qū)

一、PC Register 程序計(jì)數(shù)器

1、定義

程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,可以把它看作當(dāng)前線程正在執(zhí)行的字節(jié)碼的信號指示器。程序計(jì)數(shù)器里面記錄的是當(dāng)前線程正在執(zhí)行的那一條字節(jié)碼指令的地址。

注:如果當(dāng)前線程正在執(zhí)行的是一個本地方法,那么此時程序計(jì)數(shù)器為空。

2、作用

字節(jié)碼解釋器通過改變程序計(jì)數(shù)器來依次讀取指令,從而實(shí)現(xiàn)代碼的流程控制,如:順序執(zhí)行、選擇、循環(huán)、異常處理。

在多線程的情況下,程序計(jì)數(shù)器用于記錄當(dāng)前線程執(zhí)行的位置,從而當(dāng)線程被切換回來的時候能夠知道該線程上次運(yùn)行到哪兒了。

3、特點(diǎn)

是內(nèi)存較小的一塊空間。

線程私有。每一個線程都有一個程序計(jì)數(shù)器。

是唯一一個不會出現(xiàn)OutOfMemoryError的內(nèi)存區(qū)域。

生命周期隨著線程的創(chuàng)建而創(chuàng)建,隨著線程的結(jié)束而死亡。

二、JVM Stack 虛擬棧

1、定義

Java虛擬機(jī)棧是描述Java方法運(yùn)行過程的內(nèi)存模型。

Java虛擬機(jī)棧會為每一個即將運(yùn)行的方法分配“棧幀”空間,用于保存改方法運(yùn)行過程中所需要的一些信息,例如局部變量、操作數(shù)棧、動態(tài)鏈接、方法出口信息等。

當(dāng)這個方法執(zhí)行完后,“棧幀”中的信息出棧,并釋放內(nèi)存空間。

注意:人們常說,Java的內(nèi)存空間分為“棧”和“堆”,棧中存放局部變量,堆中存放對象。 這句話不完全正確!這里的“堆”可以這么理解,但這里的“?!敝淮砹薐ava虛擬機(jī)棧中的局部變量表部分。真正的Java虛擬機(jī)棧是由一個個棧幀組成,而每個棧幀中都擁有:局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口信息。

2、特點(diǎn)

局部變量表的創(chuàng)建是在方法被執(zhí)行的時候,隨著棧幀的創(chuàng)建而創(chuàng)建。而且,局部變量表的大小在編譯時期就確定下來了,在創(chuàng)建的時候只需分配事先規(guī)定好的大小即可。此外,在方法運(yùn)行的過程中局部變量表的大小是不會發(fā)生改變的。

Java虛擬機(jī)棧會出現(xiàn)兩種異常:

StackOverFlowError

OutOfMemoryError

a) StackOverFlowError:

若Java虛擬機(jī)棧的內(nèi)存大小不允許動態(tài)擴(kuò)展,那么當(dāng)線程請求棧的深度超過當(dāng)前Java虛擬機(jī)棧的最大深度的時候,就拋出StackOverFlowError異常。

b) OutOfMemoryError:

若Java虛擬機(jī)棧的內(nèi)存大小允許動態(tài)擴(kuò)展,且當(dāng)線程請求棧時內(nèi)存用完了,無法再動態(tài)擴(kuò)展了,此時拋出OutOfMemoryError異常。

Java虛擬機(jī)棧是線程私有的,每個線程都有各自的Java虛擬機(jī)棧,而且隨著線程的創(chuàng)建而創(chuàng)建,隨著線程的死亡而死亡。

三、Native Method Stack 本地方法棧

1、定義

本地方法棧和Java虛擬機(jī)棧實(shí)現(xiàn)的功能類似,只不過本地方法區(qū)是本地方法運(yùn)行的內(nèi)存模型。

本地方法被執(zhí)行的時候,在本地方法棧也會創(chuàng)建一個棧幀,用于存放該本地方法的局部變量表、操作數(shù)棧、動態(tài)鏈接、出口信息。

方法執(zhí)行完畢后相應(yīng)的棧幀也會出棧并釋放內(nèi)存空間。

也會拋出StackOverFlowError和OutOfMemoryError異常。

四、Head 堆

1、定義

堆是用來存在對象的內(nèi)存空間。

幾乎所有的對象都存放在堆中。

2、特點(diǎn)

線程共享 :整個Java虛擬機(jī)只有一個堆,所有的線程都訪問同一個堆。

在虛擬機(jī)啟動時創(chuàng)建。

垃圾回收的主要場所。

不同的區(qū)域存放具有不同生命周期的對象。這樣可以根據(jù)不同的區(qū)域使用不同的垃圾回收算法,從而更具有針對性,從而更高效。

堆的大小既可以固定也可以擴(kuò)展,但主流的虛擬機(jī)堆的大小是可擴(kuò)展的,因此當(dāng)線程請求分配內(nèi)存,但堆已滿,且內(nèi)存已滿無法再擴(kuò)展時,就拋出OutOfMemoryError。

五、Method Area 方法區(qū)

1、定義

Java虛擬機(jī)規(guī)范中定義方法區(qū)是堆的一個邏輯部分。

方法區(qū)中存放已經(jīng)被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等。

2、特點(diǎn)

線程共享

方法區(qū)是堆的一個邏輯部分,因此和堆一樣,都是線程共享的。整個虛擬機(jī)中只有一個方法區(qū)。

永久代

方法區(qū)中的信息一般需要長期存在,而且它又是堆的邏輯分區(qū),因此用堆的劃分方法,我們把方法區(qū)稱為老年代。

內(nèi)存回收效率低

方法區(qū)中的信息一般需要長期存在,回收一遍內(nèi)存之后可能只有少量信息無效。

對方法區(qū)的內(nèi)存回收的主要目標(biāo)是:對常量池的回收 和 對類型的卸載。

Java虛擬機(jī)規(guī)范對方法區(qū)的要求比較寬松。

和堆一樣,允許固定大小,也允許可擴(kuò)展的大小,還允許不實(shí)現(xiàn)垃圾回收。

3、常量池

方法區(qū)中存放數(shù)據(jù):類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼。其中常量存儲在運(yùn)行時常量池中。

我們一般在一個類中通過public static final來聲明一個常量。這個類被編譯后便生成Class文件,這個類的所有信息都存儲在這個class文件中。

當(dāng)這個類被Java虛擬機(jī)加載后,class文件中的常量就存放在方法區(qū)的運(yùn)行時常量池中。而且在運(yùn)行期間,可以向常量池中添加新的常量。如:String類的intern()方法就能在運(yùn)行期間向常量池中添加字符串常量。

當(dāng)運(yùn)行時常量池中的某些常量沒有被對象引用,同時也沒有被變量引用,那么就需要垃圾收集器回收。

六、直接內(nèi)存

直接內(nèi)存是除Java虛擬機(jī)之外的內(nèi)存,但也有可能被Java使用。

在NIO中引入了一種基于通道和緩沖的IO方式。它可以通過調(diào)用本地方法直接分配Java虛擬機(jī)之外的內(nèi)存,然后通過一個存儲在Java堆中的DirectByteBuffer對象直接操作該內(nèi)存,而無需先將外面內(nèi)存中的數(shù)據(jù)復(fù)制到堆中再操作,從而提升了數(shù)據(jù)操作的效率。

直接內(nèi)存的大小不受Java虛擬機(jī)控制,但既然是內(nèi)存,當(dāng)內(nèi)存不足時就會拋出OOM異常。

七、總結(jié)

1、Java虛擬機(jī)的內(nèi)存模型中一共有兩個“?!?,分別是:Java虛擬機(jī)棧和本地方法棧。

兩個“?!钡墓δ茴愃疲际欠椒ㄟ\(yùn)行過程的內(nèi)存模型。并且兩個“?!眱?nèi)部構(gòu)造相同,都是線程私有。

只不過Java虛擬機(jī)棧描述的是Java方法運(yùn)行過程的內(nèi)存模型,而本地方法棧是描述Java本地方法運(yùn)行過程的內(nèi)存模型。

2、Java虛擬機(jī)的內(nèi)存模型中一共有兩個“堆”,一個是原本的堆,一個是方法區(qū)。

方法區(qū)本質(zhì)上是屬于堆的一個邏輯部分。堆中存放對象,方法區(qū)中存放類信息、常量、靜態(tài)變量、即時編譯器編譯的代碼。

3、堆是Java虛擬機(jī)中最大的一塊內(nèi)存區(qū)域,也是垃圾收集器主要的工作區(qū)域。

4、程序計(jì)數(shù)器、Java虛擬機(jī)棧、本地方法棧是線程私有的,即每個線程都擁有各自的程序計(jì)數(shù)器、Java虛擬機(jī)棧、本地方法區(qū)。并且他們的生命周期和所屬的線程一樣。

而堆、方法區(qū)是線程共享的,在Java虛擬機(jī)中只有一個堆、一個方法棧。并在JVM啟動的時候就創(chuàng)建,JVM停止才銷毀。

2、類加載過程

Java 類加載的過程簡介
一般來說,我們把 Java 的類加載過程分為三個主要步驟:加載,連接,初始化,具體行為在 Java 虛擬機(jī)規(guī)范里有非常詳細(xì)的定義。

? ? ? ? 首先是加載過程(Loading),它是 Java 將字節(jié)碼數(shù)據(jù)從不同的數(shù)據(jù)源讀取到 JVM 中,并映射為 JVM 認(rèn)可的數(shù)據(jù)結(jié)構(gòu)(Class 對象),這里的數(shù)據(jù)源可能是各種各樣的形態(tài),比如 jar 文件,class 文件,甚至是網(wǎng)絡(luò)數(shù)據(jù)源等;如果輸入數(shù)據(jù)不是 ClassFile 的結(jié)構(gòu),則會拋出 ClassFormatError。加載階段是用戶參與的階段,我們可以自定義類加載器,去實(shí)現(xiàn)自己的類加載過程。

? ? ? ? 第二階段是連接(Linking),這是核心的步驟,簡單說是把原始的類定義信息平滑地轉(zhuǎn)入 JVM 運(yùn)行的過程中。這里可進(jìn)一步細(xì)分成三個步驟:1,驗(yàn)證(Verification),這是虛擬機(jī)安全的重要保障,JVM 需要核驗(yàn)字節(jié)信息是符合 Java 虛擬機(jī)規(guī)范的,否則就被認(rèn)為是 VerifyError,這樣就防止了惡意信息或者不合規(guī)信息危害 JVM 的運(yùn)行,驗(yàn)證階段有可能觸發(fā)更多 class 的加載。2,準(zhǔn)備(Pereparation),創(chuàng)建類或者接口中的靜態(tài)變量,并初始化靜態(tài)變量的初始值。但這里的“初始化”和下面的顯示初始化階段是有區(qū)別的,側(cè)重點(diǎn)在于分配所需要的內(nèi)存空間,不會去執(zhí)行更進(jìn)一步的 JVM 指令。3,解析(Resolution),在這一步會將常量池中的符號引用(symbolic reference)替換為直接引用。在 Java 虛擬機(jī)規(guī)范中,詳細(xì)介紹了類,接口,方法和字段等各方面的解析。

????????最后是初始化階段(initialization),這一步真正去執(zhí)行類初始化的代碼邏輯,包括靜態(tài)字段賦值的動作,以及執(zhí)行類定義中的靜態(tài)初始化塊內(nèi)的邏輯,編譯器在編譯階段就會把這部分邏輯整理好,父類型的初始化邏輯優(yōu)先于當(dāng)前類型的邏輯。再來談?wù)勲p親委派模型,簡單說就是當(dāng)加載器(Class-Loader)試圖加載某個類型的時候,除非父類加載器找不到相應(yīng)類型,否則盡量將這個任務(wù)代理給當(dāng)前加載器的父加載器去做。使用委派模型的目的是避免重復(fù)加載 Java 類型。

自定義類加載器的常見場景

? ? ? ? 實(shí)現(xiàn)類似進(jìn)程內(nèi)隔離,類加載器實(shí)際上用作不同的命名空間,以及提供類似容器,模塊化的效果。例如:1,兩個模塊依賴于某個類庫的不同版本,如果分別被不同的容器加載,就可以互不干擾。這個方面的集大成者是 Jave EE 和 OSGL,JPMS等框架。2,應(yīng)用需要從不同的數(shù)據(jù)源獲取類定義信息,例如網(wǎng)絡(luò)數(shù)據(jù)源,而不是本地文件系統(tǒng)。3,或者是需要自己操縱字節(jié)碼,動態(tài)修改生成類型。

????????我們可以總體上簡單理解自定義類加載過程:1,通過指定名稱,找到其二進(jìn)制實(shí)現(xiàn),這里往往就是自定義類加載器會“定制”的部分,例如,在特定數(shù)據(jù)源根據(jù)名字獲取字節(jié)碼,或者修改或生成字節(jié)碼。2,然后,創(chuàng)建 Class 對象,并完成類加載過程。二進(jìn)制信息到 class 對象的轉(zhuǎn)換,通常就依賴 defineClass,我們無需自己實(shí)現(xiàn),它是 final 方法。有了 Class 對象,后續(xù)完成加載過程就順利成章了。

如何降低類加載的開銷

? ? ? ? 這么多類加載,有沒有什么通用方法,不需要代碼和其他工作量,就可以降低類加載的開銷?這個可以有。

? ? ? ? 1,比如 AOT,相當(dāng)于直接編譯成機(jī)器碼,降低的其實(shí)主要是解釋和編譯開銷。但是其目前還是個實(shí)驗(yàn)特性,支持的平臺也有限,比如,JDK 9 僅支持 Linux x64,所以局限性太大,先暫且不談。

? ? ? ? 2,還有就是較少人知道的 AppCDS(Application Class-Data Sharing),CDS 在 Java 5 中被引進(jìn),但僅限于 Bootstrap Class-loader,在 8u40 中實(shí)現(xiàn)了 AppCDS,支持其他的類加載器,目前已經(jīng)在 JDK 10 中開源。

? ? ? ? 簡單來說,AppCDS 基本原理和工作過程是:首先,JVM 將類信息加載,解析成元數(shù)據(jù),并根據(jù)是否需要修改,將其分類為 Read-Only 部分和 Read-Write 部分。然后,將這些元數(shù)據(jù)直接存儲在文件系統(tǒng)中,作為所謂的 Shared Archive。第二,在應(yīng)用程序啟動時,指定歸檔文件,并開啟 AppCDS。AppCDS 改善啟動速度非常明顯,傳統(tǒng)的 Java EE 應(yīng)用,一般可以提高 20% ~ 30%以上。與此同時,降低內(nèi)存 footprint,因?yàn)橥画h(huán)境的 Java 進(jìn)程間可以共享部分?jǐn)?shù)據(jù)結(jié)構(gòu)。當(dāng)然,也不是沒有局限性,如果恰好大量使用了運(yùn)行時動態(tài)類加載,它的幫助就有限了。

3、HashMap底層實(shí)現(xiàn)原理

HashMap基于hashing原理,我們通過put()和get()方法儲存和獲取對象。當(dāng)我們將鍵值對傳遞給put()方法時,它調(diào)用鍵對象的hashCode()方法來計(jì)算hashcode,然后找到bucket位置來儲存值對象。當(dāng)獲取對象時,通過鍵對象的equals()方法找到正確的鍵值對,然后返回值對象。HashMap使用鏈表來解決碰撞問題,當(dāng)發(fā)生碰撞了,對象將會儲存在鏈表的下一個節(jié)點(diǎn)中。 HashMap在每個鏈表節(jié)點(diǎn)中儲存鍵值對對象。

當(dāng)兩個不同的鍵對象的hashcode相同時會發(fā)生什么? 它們會儲存在同一個bucket位置的鏈表中。鍵對象的equals()方法用來找到鍵值對。

HashMap實(shí)現(xiàn)了Map接口,Map接口對鍵值對進(jìn)行映射。Map中不允許重復(fù)的鍵。Map接口有兩個基本的實(shí)現(xiàn),HashMap和TreeMap。TreeMap保存了對象的排列次序,而HashMap則不能。HashMap允許鍵和值為null。HashMap是非synchronized的,但collection框架提供方法能保證HashMap synchronized,這樣多個線程同時訪問HashMap時,能保證只有一個線程更改Map。

HashMap和Hashtable的區(qū)別:

HashMap和Hashtable都實(shí)現(xiàn)了Map接口,但決定用哪一個之前先要弄清楚它們之間的分別。主要的區(qū)別有:線程安全性,同步(synchronization),以及速度。

1.HashMap幾乎可以等價于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受為null的鍵值(key)和值(value),而Hashtable則不行)。

2.HashMap是非synchronized,而Hashtable是synchronized,這意味著Hashtable是線程安全的,多個線程可以共享一個Hashtable;而如果沒有正確的同步的話,多個線程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴(kuò)展性更好。

3.另一個區(qū)別是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以當(dāng)有其它線程改變了HashMap的結(jié)構(gòu)(增加或者移除元素),將會拋出ConcurrentModificationException,但迭代器本身的remove()方法移除元素則不會拋出ConcurrentModificationException異常。但這并不是一個一定發(fā)生的行為,要看JVM。這條同樣也是Enumeration和Iterator的區(qū)別。

4.由于Hashtable是線程安全的也是synchronized,所以在單線程環(huán)境下它比HashMap要慢。如果你不需要同步,只需要單一線程,那么使用HashMap性能要好過Hashtable。

5.HashMap不能保證隨著時間的推移Map中的元素次序是不變的。

tip:HashMap可以通過下面的語句進(jìn)行同步:Map m = Collections.synchronizeMap(hashMap);

HashMap和HashSet的區(qū)別:

HashMap和HashSet的區(qū)別是Java面試中最常被問到的問題。如果沒有涉及到Collection框架以及多線程的面試,可以說是不完整。而Collection框架的問題不涉及到HashSet和HashMap,也可以說是不完整。HashSet是collection框架的一部分,它們讓我們能夠使用對象的集合。collection框架有自己的接口和實(shí)現(xiàn),主要分為Set接口,List接口和Queue接口。它們有各自的特點(diǎn),Set的集合里不允許對象有重復(fù)的值,List允許有重復(fù),它對集合中的對象進(jìn)行索引,Queue的工作原理是FCFS算法(First Come, First Serve)。

HashSet實(shí)現(xiàn)了Set接口,它不允許集合中有重復(fù)的值,當(dāng)我們提到HashSet時,第一件事情就是在將對象存儲在HashSet之前,要先確保對象重寫equals()和hashCode()方法,這樣才能比較對象的值是否相等,以確保set中沒有儲存相等的對象。如果我們沒有重寫這兩個方法,將會使用這個方法的默認(rèn)實(shí)現(xiàn)。

*HashMap*? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*HashSet*

HashMap實(shí)現(xiàn)了Map接口? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? HashSet實(shí)現(xiàn)了Set接口

HashMap儲存鍵值對? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?HashSet僅僅存儲對象

使用put()方法將元素放入map中? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 使用add()方法將元素放入set中

HashMap中使用鍵對象來計(jì)算hashcode值? ? ? ? ? ? ? ? HashSet使用成員對象來計(jì)算hashcode值,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?對于兩個對象來說hashcode可能相同,所以? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? equals()方法用來判斷對象的相等性,如果兩個? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?對象不同的話,那么返回false

HashMap比較快,因?yàn)槭鞘褂梦ㄒ坏逆I來獲取對象? ? HashSet較HashMap來說比較慢


4、多線程,線程池以及synchronize關(guān)鍵字

流程圖如下:

? ? ?線程池學(xué)習(xí)流程圖

5、Handler原理


示意圖

6、動畫實(shí)現(xiàn)原理

Frame Animation 幀動畫,通過順序播放一系列圖像從而產(chǎn)生動畫效果,。圖片過多時容易造成OOM(Out Of Memory內(nèi)存用完)異常。

Tween Animation?補(bǔ)間動畫(又叫view動畫),是通過對場景里的對象不斷做圖像變換(透明度、縮放、平移、旋轉(zhuǎn))從而產(chǎn)生動畫效果,是一種漸進(jìn)式動畫,并且View動畫支持自定義。

Accribute Animation 屬性動畫,這也是在android3.0之后引進(jìn)的動畫,在手機(jī)的版本上是android4.0就可以使用這個動 畫,通過動態(tài)的改變對象的屬性從而達(dá)到動畫效果。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 所有知識點(diǎn)已整理成app app下載地址 J2EE 部分: 1.Switch能否用string做參數(shù)? 在 Jav...
    侯蛋蛋_閱讀 2,710評論 1 4
  • Java SE 基礎(chǔ): 封裝、繼承、多態(tài) 封裝: 概念:就是把對象的屬性和操作(或服務(wù))結(jié)合為一個獨(dú)立的整體,并盡...
    Jayden_Cao閱讀 2,247評論 0 8
  • 一、運(yùn)行時數(shù)據(jù)區(qū)域 Java虛擬機(jī)管理的內(nèi)存包括幾個運(yùn)行時數(shù)據(jù)內(nèi)存:方法區(qū)、虛擬機(jī)棧、本地方法棧、堆、程序計(jì)數(shù)器,...
    加油小杜閱讀 1,588評論 1 15
  • 《深入理解Java虛擬機(jī)》筆記_第一遍 先取看完這本書(JVM)后必須掌握的部分。 第一部分 走近 Java 從傳...
    xiaogmail閱讀 5,473評論 1 34
  • 老公的大姐終于搬新家了。這套房子是她結(jié)婚20余年后第一套真正意義上的家。 房子不大,兩居室,才90方,經(jīng)過姐夫大半...
    莊心愛寫作閱讀 706評論 0 4

友情鏈接更多精彩內(nèi)容