2018最新安卓面試大全(含BAT,網易,滴滴)----你面不上BAT的原因:面經寶典,都在這裡啦
廢話不多說,直接進入正題。
童鞋們可以掃碼右側二維碼,加入微信群,分享你的面試經歷哦~
Java篇
1.Java中sleep、wait、yield、join的區別?
比較項 | 歸屬 | 是否釋放鎖 | 使用範圍 | 是否需要捕獲異常 | 是否能自我喚醒 | 進入狀態 |
---|---|---|---|---|---|---|
sleep | Thread類 | 沒有釋放 | 任何地方 | 是 | 是 | Blocked |
wait | Object類 | 釋放 | 同步控制方法或者同步控制塊中 | 否 | 否 | Blocked |
yield | Thread類 | 沒有釋放 | 任何地方 | 是 | 有可能 | runnable |
join | Thread類 | 沒有釋放 | 任何地方 | 是 | 能 | runnable |
總結:
sleep是Thread類中的靜態方法。無論是在a執行緒中呼叫b的sleep方法,還是b執行緒中呼叫a的sleep方法,誰呼叫,誰睡覺。
2.throw和throws有什麼區別?
1、throws出現在方法函式頭;而throw出現在函式體。
2、throws表示出現異常的一種可能性,並不一定會發生這些異常;throw則是丟擲了異常,執行throw則一定丟擲了某種異常。
3、兩者都是消極處理異常的方式(這裡的消極並不是說這種方式不好),只是丟擲或者可能丟擲異常,但是不會由函式去處理異常,真正的處理異常由函式的上層呼叫處理。
void doA(int a) throws Exception1,Exception3{
try{
......
}catch(Exception1 e){
throw e;
}catch(Exception2 e){
System.out.println("出錯了!");
}
if(a!=b)
throw new Exception3("自定義異常");
}
3.介面和抽象類的區別是什麼?
1、Java提供和支援建立抽象類和介面。它們的實現有共同點,不同點在於:
2、介面中所有的方法隱含的都是抽象的。而抽象類則可以同時包含抽象和非抽象的方法。
3、類可以實現很多個介面,但是隻能繼承一個抽象類
4、類可以不實現抽象類和介面宣告的所有方法,當然,在這種情況下,類也必須得宣告成是抽象的。
5、抽象類可以在不提供介面方法實現的情況下實現介面。
6、Java介面中宣告的變數預設都是final的。抽象類可以包含非final的變數。
7、Java介面中的成員函式預設是public的。抽象類的成員函式可以是private,protected或者是public。
8、介面是絕對抽象的,不可以被例項化。抽象類也不可以被例項化,但是,如果它包含main方法的話是可以被呼叫的。
4.為什麼介面中只能定義常量?
從上一道問題的6,7中我們其實已經可以得到答案了。
介面中只能定義常量,即使你的程式碼是這樣寫的:public int a,底層語言也會預設加上public static final int a轉為常量,那麼這是為什麼呢?
我們都知道,介面中不能定義方法的實現,但是抽象類中是可以定義變數、常量以及方法的實現的,所以我們可以將介面看為比抽象類更高層次的抽象,是特殊的抽象類。加入介面可以定義變數,因為介面中的方法都是抽象的,我們無法通過行為,例如set()方法來修改這一屬性值。
5.Java支援多繼承麼?
Java中類不支援多繼承,只支援單繼承(即一個類只有一個父類)。 但是java中的介面支援多繼承,,即一個子介面可以有多個父介面。(介面的作用是用來擴充套件物件的功能,一個子介面繼承多個父介面,說明子介面擴充套件了多個功能,當類實現介面時,類就擴充套件了相應的功能)。
6.什麼是Java虛擬機器?為什麼Java被稱作是“平臺無關的程式語言”?
Java虛擬機器是一個可以執行Java位元組碼的虛擬機器程序。Java原始檔被編譯成能被Java虛擬機器執行的位元組碼檔案。
Java是平臺無關的語言是指用Java寫的應用程式不用修改就可在不同的軟硬體平臺上執行。平臺無關有兩種:原始碼級和目的碼級。C和C++具有一定程度的原始碼級平臺無關,表明用C或C++寫的應用程式不用修改只需重新編譯就可以在不同平臺上執行。
Java主要靠Java虛擬機器(JVM)在目標碼級實現平臺無關性。JVM是一種抽象機器,它附著在具體作業系統之上,本身具有一套虛機器指令,並有自己的棧、暫存器組等。但JVM通常是在軟體上而不是在硬體上實現。(目前,SUN系統公司已經設計實現了Java晶片,主要使用在網路計算機NC上。另外,Java晶片的出現也會使Java更容易嵌入到家用電器中。)JVM是Java平臺無關的基礎,在JVM上,有一個Java直譯器用來解釋Java編譯器編譯後的程式。Java程式設計人員在編寫完軟體後,通過Java編譯器將Java源程式編譯為JVM的位元組程式碼。任何一臺機器只要配備了Java直譯器,就可以執行這個程式,而不管這種位元組碼是在何種平臺上生成的。另外,Java採用的是基於IEEE標準的資料型別。通過JVM保證資料型別的一致性,也確保了Java的平臺無關性。從上面可以看出java屬於半編譯,半解釋型語言:
java的編譯器先將其編譯為class檔案,也就是位元組碼;然後將位元組碼交由jvm(java虛擬機器)解釋執行;
7.JAVA中常用的資料結構
相關問題:
7.1HashMap和Hashtable的區別?
1.兩者最主要的區別在於Hashtable是執行緒安全,而HashMap則非執行緒安全
2.HashMap可以使用null作為key,而Hashtable則不允許null作為key
3.兩者計算hash的方法不同
- Hashtable計算hash是直接使用key的hashcode對table陣列的長度直接進行取模
- HashMap計算hash對key的hashcode進行了二次hash,以獲得更好的雜湊值,然後對table陣列長度取摸
4.HashMap和Hashtable的底層實現都是陣列+連結串列結構實現
7.2HashSet和HashMap的區別?
7.3我們能否讓HashMap同步?
HashMap可以通過下面的語句進行同步:
Map m = Collections.synchronizeMap(hashMap);
8.synchronized 和volatile 關鍵字的作用/區別?
作用:
1)保證了不同執行緒對這個變數進行操作時的可見性,即一個執行緒修改了某個變數的值,這新值對其他執行緒來說是立即可見的。
2)禁止進行指令重排序。
區別:
volatile 本質是在告訴jvm 當前變數在暫存器(工作記憶體)中的值是不確定的,需要從主存中讀取;synchronized 則是鎖定當前變數,只有當前執行緒可以訪問該變數,其他執行緒被阻塞住。
1.volatile 僅能使用在變數級別;synchronized 則可以使用在變數、方法、和類級別的
2.volatile 僅能實現變數的修改可見性,並不能保證原子性;synchronized 則可以保證變數的修改可見性和原子性
3.volatile 不會造成執行緒的阻塞;synchronized 可能會造成執行緒的阻塞。
4.volatile 標記的變數不會被編譯器優化;synchronized 標記的變數可以被編譯器優化
9.JAVA靜態方法是否可以被繼承?
java中靜態屬性和靜態方法可以被繼承,但是沒有被重寫(overwrite)而是被隱藏.
10.簡述class載入各階段,Class Loader有哪些模型。
在java應用程式開發中,只有被jvm裝載的class型別才能在程式中使用。只要生成的位元組碼符合jvm指令集和檔案格式,就可以在jvm上執行,這為java的跨平臺性提供條件。
位元組碼的裝載過程分為3個階段:載入,連線,初始化。其中連線包括3個步驟(驗證,準備,解析)。
1)載入:處於class裝載的第一個階段,這時jvm必須完成通過類的全面獲取類的二進位制資料流,解析類的二進位制資料流為方法區內的資料結構,建立java.lang.Class的例項。
2)連線:
- 驗證:驗證位元組碼檔案,保證載入的位元組碼是符合規範的。
- 準備:正式為類變數(static修飾的變數)分配記憶體,並設定內變數的初始值,這些記憶體都將在方法區進行分配(不包括例項變數)。
- 解析:將類,介面,方法和欄位的應用轉為直接引用。
3)初始化:如果前面的步驟都沒有出現問題,那麼表示類可以順利的裝載到系統中。這個時候才會執行java位元組碼。初始化階段的主要工作是執行類的初始化方法。
Class Loader是一個物件,主要是對類的請求提供服務,當jvm需要某個類是它根據名稱向ClassLoader請求這個類,然後ClassLoader返回這個類的class物件。
1)引導類載入器(Bootstrap Class Loader):它用來載入java的核心庫,使用源生程式碼來實現的。
2)擴充套件類載入器(Extensions Class Loader):用來載入java的擴充套件庫。jvm的實現會提供一個擴充套件庫目錄,該類載入器在目錄中尋找並載入java類。
3)系統類載入器(System Class Loader):一般來講,java應用的類都是由它載入完成的,是根據java的應用類路徑來載入java類。
11.多執行緒死鎖的產生以及如何避免死鎖?
死鎖:多執行緒以及多程序改善了系統資源的利用率並提高了系統 的處理能力。然而,併發執行也帶來了新的問題——死鎖。所謂死鎖是指多個執行緒因競爭資源而造成的一種僵局(互相等待),若無外力作用,這些程序都將無法向前推進。
滿足以下四個條件,只要其中任一條件不成立,死鎖就不會發生。
- 互斥條件:程序要求對所分配的資源(如印表機)進行排他性控制,即在一段時間內某 資源僅為一個程序所佔有。此時若有其他程序請求該資源,則請求程序只能等待。
- 不剝奪條件:程序所獲得的資源在未使用完畢之前,不能被其他程序強行奪走,即只能 由獲得該資源的程序自己來釋放(只能是主動釋放)。
- 請求和保持條件:程序已經保持了至少一個資源,但又提出了新的資源請求,而該資源 已被其他程序佔有,此時請求程序被阻塞,但對自己已獲得的資源保持不放。
- 迴圈等待條件:存在一種程序資源的迴圈等待鏈,鏈中每一個程序已獲得的資源同時被 鏈中下一個程序所請求。即存在一個處於等待狀態的程序集合{Pl, P2, …, pn},其中Pi等 待的資源被P(i+1)佔有(i=0, 1, …, n-1),Pn等待的資源被P0佔有,如圖2-15所示。
12.Java Synchronize 和 Lock 的區別與用法
synchronized:在需要同步的物件中加入此控制,synchronized可以加在方法上,也可以加在特定程式碼塊中,括號中表示需要鎖的物件。
lock:需要顯示指定起始位置和終止位置。一般使用ReentrantLock類做為鎖,多個執行緒中必須要使用一個ReentrantLock類做為物件才能保證鎖的生效。且在加鎖和解鎖處需要通過lock()和unlock()顯示指出。所以一般會在finally塊中寫unlock()以防死鎖。
Android篇
1.Activity的生命週期?
2.什麼情況下Activity就不會得到完整的生命週期回撥?
在onCreate()中呼叫Activity的finish()方法,這時候會直接進入onDestory(),而不會產生其他中間過程的回撥,即onCreate()->onDestory()。這個我們可以應用到類似跳轉功能的Activity中,在onCreate()進行邏輯處理後,開啟目標Activity,然後finish()。這種情況下,使用者不會看到這個Activity,這個Activity充當一個分發者的角色。
某個生命週期發生了crash,如在onCreate()中就發生了crash,就不會有下面生命週期的回調了。
3.Service的生命週期
一張圖帶你看懂Service的生命週期。
這裡需要注意通過 如果一個Service
被startService
方法多次啟動,那麼onCreate
方法只會呼叫一次,onStart
將會被呼叫多次(對應呼叫startService
的次數),並且系統只會建立Service
的一個例項。
4.Service是否在main thread中執行, service裡面是否能執行耗時的操作?
Service不是獨立的程序,也不是獨立的執行緒,它是依賴於應用程式的主執行緒的,也就是說,在更多時候不建議在Service中編寫耗時的邏輯和操作(比如:網路請求,拷貝資料庫,大檔案),否則會引起ANR。
如果想在服務中執行耗時的任務。有以下解決方案:
1) 在service中開啟一個子執行緒
2)可以使用IntentService非同步管理服務
3給server開個獨立程序
附:在Service中執行的耗時操作最多20秒,BroadcastReceiver是10秒,Activity是5秒。
5.context.startService 和context.bindService應用場景?
跨程序使用
context.bindServer
(不過也要看具體業務,如果和activity生命週期關聯緊密使用context.bindServer也是可以的)
同一個程序建議使用context.startServer
6.Activity的幾種啟動模式?
standard 模式
預設模式: 每次啟用Activity時都會建立Activity例項,並放入任務棧中。
使用場景:大多數Activity。
singleTop 模式
如果在任務的棧頂正好存在該Activity的例項,就重用該例項( 會呼叫例項的 onNewIntent() ),否則就會建立新的例項並放入棧頂,即使棧中已經存在該Activity的例項,只要不在棧頂,都會建立新的例項。
使用場景: 如新聞類或者閱讀類App的內容頁面。
singleTask 模式
如果在棧中已經有該Activity的例項,就重用該例項(會呼叫例項的 onNewIntent() )。重用時,會讓該例項回到棧頂,因此在它上面的例項將會被移出棧。如果棧中不存在該例項,將會建立新的例項放入棧中。
使用場景: 如瀏覽器的主介面。不管從多少個應用啟動瀏覽器,只會啟動主介面一次,其餘情況都會走onNewIntent,並且會清空主介面上面的其他頁面。
附:每個應用都有一個task(可以理解為程序),singleTask在啟動的時候,會先在系統中查詢屬性值affinity等於它的屬性值taskAffinity的任務存在
singleInstance 模式
在一個新棧中建立該Activity的例項,並讓多個應用共享該棧中的該Activity例項。一旦該模式的Activity例項已經存在於某個棧中,任何應用再啟用該Activity時都會重用該棧中的例項( 會呼叫例項的 onNewIntent() )。其效果相當於多個應用共享一個應用,不管誰啟用該 Activity 都會進入同一個應用中。
使用場景: 如鬧鈴提醒,將鬧鈴提醒與鬧鈴設定分離;電話。singleInstance不要用於中間頁面,如果用於中間頁面,跳轉會有問題,比如:A -> B (singleInstance) -> C,完全退出後,在此啟動,首先開啟的是B。
附:singleTask
和 singleInstance
還有效能上的區別,singleInstance
儘量少用,與其說singleInstance
獨佔一個task,還不如說佔用一個程序。
7.應用setContentView與LayoutInflater載入解析機制?
1)xml怎麼顯示的?
2)在java檔案設定Activity的屬性時為什麼必須在setContentView方法之前呼叫requestFeature()?
3)Activity調運setContentView方法自身會顯示佈局嗎?
總結:
1)建立一個DecorView的物件mDecor,該mDecor物件將作為整個應用視窗的根檢視。
2)依據Feature等style theme建立不同的視窗修飾佈局檔案,並且通過findViewById獲取Activity佈局檔案該存放的地方(視窗修飾佈局檔案中id為content的FrameLayout)。
3)將Activity的佈局檔案新增至id為content的FrameLayout內。
4)當setContentView設定顯示OK以後會回撥Activity的onContentChanged方法。Activity的各種View的findViewById()方法等都可以放到該方法中,系統會幫忙回撥。
5)當啟動Activity調運完ActivityThread的main方法之後,接著呼叫ActivityThread類performLaunchActivity來建立要啟動的Activity元件,在建立Activity元件的過程中,還會為該Activity元件建立視窗物件和檢視物件;接著Activity元件建立完成之後,通過呼叫ActivityThread類的handleResumeActivity中r.activity.makeVisible()將它啟用。呼叫Activity的makeVisible方法顯示我們上面通過setContentView建立的mDecor檢視族。
圖中id為content的內容就是整個View樹的結構,所以對每個具體View物件的操作,其實就是個遞迴的實現。
8.Android應用層View繪製流程
相關問題:
對MeasureSpec 的理解?
參考文章:
先上圖:
整個View樹的繪圖流程是在ViewRootImpl類的performTraversals()方法,該函式做的執行過程主要是根據之前設定的狀態,判斷是否重新計算檢視大小(measure)、是否重新放置檢視的位置(layout)、以及是否重繪 (draw).
從圖中可以看出,分為三步:
1)measure過程
2)layout過程
3)draw過程
第一步:measure過程
- measure過程主要就是從頂層父View向子View遞迴呼叫view.measure方法(measure中又回撥onMeasure方法)的過程.
- View的measure方法是final的,不允許重寫,View子類只能重寫onMeasure來完成自己的測量邏輯。
- View的佈局大小由父View和子View共同決定。
- 使用View的getMeasuredWidth()和getMeasuredHeight()方法來獲取View測量的寬高,必須保證這兩個方法在onMeasure流程之後被呼叫才能返回有效值。
第二步:layout過程
- View.layout方法可被重寫,ViewGroup.layout為final的不可重寫,ViewGroup.onLayout為abstract的,子類必須重寫實現自己的位置邏輯。
- measure操作完成後得到的是對每個View經測量過的measuredWidth和measuredHeight,layout操作完成之後得到的是對每個View進行位置分配後的mLeft、mTop、mRight、mBottom,這些值都是相對於父View來說的。
- 凡是layout_XXX的佈局屬性基本都針對的是包含子View的ViewGroup的,當對一個沒有父容器的View設定相關layout_XXX屬性是沒有任何意義的
- 使用View的getWidth()和getHeight()方法來獲取View測量的寬高,必須保證這兩個方法在onLayout流程之後被呼叫才能返回有效值。
第三步:draw過程
- 第一步:對View的背景進行繪製。
- 第二步,對View的內容進行繪製。
- 第三步,對當前View的所有子View進行繪製,如果當前的View沒有子View就不需要進行繪製。
- 第四步,對View的滾動條進行繪製。
9.Android事件分發
1)為什麼會出現事件分發機制?
2)當手指點選螢幕開始,這些動作在各層之間如何傳遞?
【1】事件分發dispatchTouchEvent(MotionEvent ev)
【2】事件攔截 onInterceptTouchEvent(MotionEvent ev)
【3】事件響應 onTouchEvent(MotionEvent ev)
其中ViewGroup以及繼承ViewGroup的容器控制元件如佈局檔案RelativeLayout等,需回撥這三個方法;通常View則只回調【1】【3】,對應一些顯示控制元件如button等。
11.點九圖的使用
14. Looper、Handler、Message三者關係?
Looper主要作用:
1、 與當前執行緒繫結,保證一個執行緒只會有一個Looper例項,同時一個Looper例項也只有一個MessageQueue。
2、 loop()方法,不斷從MessageQueue中去取訊息,交給訊息的target屬性的dispatchMessage去處理。
好了,我們的非同步訊息處理執行緒已經有了訊息佇列(MessageQueue),也有了在無限迴圈體中取出訊息的哥們,現在缺的就是傳送訊息的物件了,於是乎:Handler登場了。
13.深入解析Looper.prepare()和Looper.loop()?
Looper類用來為一個執行緒開啟一個訊息迴圈。 預設情況下android中新誕生的執行緒是沒有開啟訊息迴圈的。(主執行緒除外,主執行緒系統會自動為其建立Looper物件,開啟訊息迴圈。) Looper物件通過MessageQueue來存放訊息和事件。一個執行緒只能有一個Looper,對應一個MessageQueue。
15.Android程序如何保活?
⚠️:程序的優先順序?
Android 程序拉活包括兩個層面:
A. 提供程序優先順序,降低程序被殺死的概率
B. 在程序被殺死後,進行拉活程序的優先順序
1.前臺程序
2.可見程序
3.服務程序
4.後臺程序
5.空程序
16.Android 中的幾種動畫?
總的來說,Android動畫可以分為兩類,最初的傳統動畫和Android3.0 之後出現的屬性動畫;
傳統動畫又包括 幀動畫(Frame Animation)和補間動畫(Tweened Animation)。
17.如何載入大圖?如何載入多圖?
1)BitmapFactory.Options引數的inJustDecodeBounds屬性設定為true,可以讓解析方法禁止為bitmap分配記憶體
2)最核心的類是LruCache (此類在android-support-v4的包中提供) 。這個類非常適合用來快取圖片,它的主要演算法原理是把最近使用的物件用強引用儲存在 LinkedHashMap 中,並且把最近最少使用的物件在快取值達到預設定值之前從記憶體中移除
18.安卓有序廣播、無序廣播、靜態廣播、動態廣播?
動態/靜態
程式碼中動態註冊:不是常駐型廣播,也就是說廣播跟隨程式的生命週期。
在Manifest.xml中靜態註冊:是常駐型,也就是說當應用程式關閉後,如果有資訊廣播來,程式也會被系統呼叫自動執行。
無序/有序
無序廣播:所有的接收者都會接收事件,不可以被攔截,不可以被修改。
有序廣播:按照優先順序,一級一級的向下傳遞,接收者可以修改廣播資料,也可以終止廣播事件。
19.講解一下context?
⚠️:注意事項:
1) 單例中錯誤使用activity的context
2) 在Application的構造起裡呼叫context方法會crash
20.Android從哪些方面可以優化佈局?
1)include
2)merge
3)viewStub(不可以與merge同時使用,會增加繪製層數,如何取捨看具體業務)
21.Serializable和Parcelable的區別?
1.Parcelable的速度比高十倍以上
2.Serializable的迷人之處在於你只需要對某個類以及它的屬性實現Serializable 介面即可。Serializable 介面是一種標識介面(marker interface),這意味著無需實現方法,Java便會對這個物件進行高效的序列化操作。
3.Parcelable方式的實現原理是將一個完整的物件進行分解,而分解後的每一部分都是Intent所支援的資料型別,這樣也就實現傳遞物件的功能了
22.Android跨程序通訊的幾種方式
參考文章:
Android跨程序通訊的四種方式
方式一:訪問其他應用程式的Activity【intent、AMS兩種方式】
方式二:Content Provider
方式三:廣播(Broadcast)
方式四:AIDL服務【包括:Message(內部封裝的還是AIDL)】
相關知識點:
Messenger與AIDL的異同
Android 基於Message的程序間通訊 Messenger完全解析
23.Android 中的Binder跨程序通訊機制與AIDL?
程序:一個JVM就是一個程序
執行緒:最小的排程單元
一個程序可以包含多個執行緒,在安卓中有一個主執行緒也就是UI執行緒,UI執行緒才可以操作介面,如果在一個執行緒裡面進行大量耗時操作在安卓中就會出現ANR(Application Not Responding)
- Client、Server和Service Manager實現在使用者空間中,Binder驅動程式實現在核心空間中
- Binder驅動程式和Service Manager在Android平臺中已經實現,開發者只需要在使用者空間實現自己的Client和Server
- Binder驅動程式提供裝置檔案/dev/binder與使用者空間互動,Client、Server和Service Manager通過open和ioctl檔案操作函式與Binder驅動程式進行通訊
- Client和Server之間的程序間通訊通過Binder驅動程式間接實現
- Service Manager是一個守護程序,用來管理Server,並向Client提供查詢Server介面的能力
========================明確以下幾個問題==========================
1.為什麼需要跨程序通訊?
2.為什麼在Android中使用Binder進行跨程序通訊?
3.Binder是什麼?
4.如何使用Binder進行跨程序通訊呢?
24.Dalvik和ART的區別?
Dalvik與JVM的區別
(1)Dalvik指令集是基於暫存器的架構,dex位元組碼更適合於記憶體和處理器速度有限的系統。
(2)而JVM是基於棧的。相對而言,基於暫存器的Dalvik實現雖然犧牲了一些平臺無關性,但是它在程式碼的執行效率上要更勝一籌。
(3)Dalvik 是Android4.4及以下平臺的虛擬機器。Art 是在Android4.4以上平臺使用的虛擬機器。
ART的優點:
ART 效能高於採用JIT的Dalvik
應用啟動更快、執行更快、體驗更流暢、觸感反饋更及時
更長的電池續航能力
支援更低的硬體ART的缺點:
位元組碼變為機器碼之後,佔用的儲存空間更大
應用的安裝時間會變長。
25.如何檢測記憶體洩漏以及記憶體優化
參考文章:
=======================明確如下幾個問題==========================
1.如何檢測記憶體洩露?
2.如何追蹤記憶體分配
3.如何查詢方法執行的時間?
Java 中的記憶體分配
1.靜態儲存區:編譯時就分配好,在程式整個執行期間都存在。它主要存放靜態資料和常量;
2.棧區:當方法執行時,會在棧區記憶體中建立方法體內部的區域性變數,方法結束後自動釋放記憶體;
3.堆區:通常存放 new 出來的物件。由 Java 垃圾回收器回收。
常見的記憶體洩漏案例
case 1. 單例造成的記憶體洩露
case 2. InnerClass匿名內部類
case 3. Activity Context 的不正確使用
case 4. Handler引起的記憶體洩漏
case 5. 註冊監聽器的洩漏
case 6. Cursor,Stream沒有close,View沒有recyle
case 7. 集合中物件沒清理造成的記憶體洩漏
case 8. WebView造成的洩露
case 9. 構造Adapter時,沒有使用快取的ConvertView
26.Android O 新特性
參考文章:
一些新特性:
通知渠道 — Notification Channels
畫中畫模式 — PIP
自適應圖示 — Adaptive Icons
固定快捷方式和小部件 — Pinning shortcuts
……
……
27.Android元件化和外掛化區別
參考文章:
元件化開發就是將一個app分成多個模組,每個模組都是一個元件(Module),開發的過程中我們可以讓這些元件相互依賴或者單獨除錯部分元件等,但是最終釋出的時候是將這些元件合併統一成一個apk,這就是元件化開發。
外掛化開發和元件化開發略有不用,外掛化開發時將整個app拆分成很多模組,這些模組包括一個宿主和多個外掛,每個模組都是一個apk(元件化的每個模組是個lib),最終打包的時候將宿主apk和外掛apk分開或者聯合打包。
28.WebView效能分析與優化
參考文章:
資料結構與演算法篇
1.java堆和棧在記憶體中的區別/應用?
==================區別==================
1、應用程式所有的部分都使用堆記憶體,然後棧記憶體通過一個執行緒執行來使用。
2、不論物件什麼時候建立,他都會儲存在堆記憶體中,棧記憶體包含它的引用。棧記憶體只包含原始值變數和堆中物件變數的引用。
3、儲存在堆中的物件是全域性可以被訪問的,然而棧記憶體不能被其他執行緒所訪問。
4、棧中的記憶體管理使用LIFO的方式完成,而堆記憶體的管理要更復雜了,因為它是全域性被訪問的。堆記憶體被分為,年輕一代,老一代等等,更多的細節請看,這篇文章
5、棧記憶體是生命週期很短的,然而堆記憶體的生命週期從程式的執行開始到執行結束。
6、我們可以使用-Xms和-Xmx JVM選項定義開始的大小和堆記憶體的最大值,我們可以使用-Xss定義棧的大小
7、當棧記憶體滿的時候,Java丟擲java.lang.StackOverFlowError異常而堆記憶體滿的時候丟擲java.lang.OutOfMemoryError: Java Heap Space錯誤
8、和堆記憶體比,棧記憶體要小的多,因為明確使用了記憶體分配規則(LIFO),和堆記憶體相比棧記憶體非常快。
9.堆溢位:不斷的new 一個物件,一直建立新的物件; 棧溢位:死迴圈或者是遞迴太深
==================應用==================
1、類變數(static修飾的變數):在程式載入時系統就為它在堆中開闢了記憶體,堆中的記憶體地址存放於棧以便於高速訪問。靜態變數的生命週期–一直持續到整個”系統”關閉
2、例項變數:當你使用java關鍵字new的時候,系統在堆中開闢並不一定是連續的空間分配給變數(比如說類例項),然後根據零散的堆記憶體地址,通過雜湊演算法換算為一長串數字以表徵這個變數在堆中的”物理位置”。 例項變數的生命週期–當例項變數的引用丟失後,將被GC(垃圾回收器)列入可回收“名單”中,但並不是馬上就釋放堆中記憶體
3、區域性變數:區域性變數,由宣告在某方法,或某程式碼段裡(比如for迴圈),執行到它的時候在棧中開闢記憶體,當局部變數一但脫離作用域,記憶體立即釋放
2.寫出快速排序和氣泡排序
/**
* 氣泡排序
* 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
* 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。
* 針對所有的元素重複以上的步驟,除了最後一個。
* 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。
* @param numbers 需要排序的整型陣列
*/
public static void bubbleSort(int[] numbers)
{
int temp = 0;
int size = numbers.length;
for(int i = 0 ; i < size-1; i ++)
{
for(int j = 0 ;j < size-1-i ; j++)
{
if(numbers[j] > numbers[j+1]) //交換兩數位置
{
temp = numbers[j];
numbers[j] = numbers[j+1];
numbers[j+1] = temp;
}
}
}
}
public class FastSort{
public static void main(String []args){
System.out.println("Hello World");
int[] a = {12,20,5,16,15,1,30,45,23,9};
int start = 0;
int end = a.length-1;
sort(a,start,end);
for(int i = 0; i<a.length; i++){
System.out.println(a[i]);
}
}
/**
* 查找出中軸(預設是最低位low)的在numbers陣列排序後所在位置
*
* @param numbers 帶查詢陣列
* @param low 開始位置
* @param high 結束位置
* @return 中軸所在位置
*/
public void sort(int[] a,int low,int high){
int start = low;
int end = high;
int key = a[low];
while(end>start){
//從後往前比較
while(end>start&&a[end]>=key) //如果沒有比關鍵值小的,比較下一個,直到有比關鍵值小的交換位置,然後又從前往後比較
end--;
if(a[end]<=key){
int temp = a[end];
a[end] = a[start];
a[start] = temp;
}
//從前往後比較
while(end>start&&a[start]<=key)//如果沒有比關鍵值大的,比較下一個,直到有比關鍵值大的交換位置
start++;
if(a[start]>=key){
int temp = a[start];
a[start] = a[end];
a[end] = temp;
}
//此時第一次迴圈比較結束,關鍵值的位置已經確定了。左邊的值都比關鍵值小,右邊的值都比關鍵值大,但是兩邊的順序還有可能是不一樣的,進行下面的遞迴呼叫
}
//遞迴
if(start>low) sort(a,low,start-1);//左邊序列。第一個索引位置到關鍵值索引-1
if(end<high) sort(a,end+1,high);//右邊序列。從關鍵值索引+1到最後一個
}
}
3.你所知道的排序時空複雜度和穩定性
參考文章:
網路篇
未完待續。。。
設計模式篇
1.觀察者模式
觀察者模式是一個使用頻率非常高的模式,他最常用的地方是GUI系統和訂閱-釋出系統。
該模式的最重要的作用就是解耦,使觀察者和被觀察者之間依賴儘可能小,甚至好無依賴。
未完待續。。。
未完待續。。。。。。。持續更新中。。。。。。。。。。
未完待續。。。。。。。持續更新中。。。。。。。。。。
未完待續。。。。。。。持續更新中。。。。。。。。。。
未完待續。。。。。。。持續更新中。。。。。。。。。。
童鞋們,請持續關注本文,會持續跟新!!!!!!
掃碼關注公眾號“偉大程式猿的誕生“,更多幹貨等著你~
掃碼關注公眾號“偉大程式猿的誕生“,更多幹貨等著你~
掃碼關注公眾號“偉大程式猿的誕生“,更多幹貨等著你~
公眾號回覆“資料獲取”,獲取更多幹貨哦~