面試的時候總會遇到一些各種各樣的面試題,而且這些面試題很多都是關于平時容易疏忽的理論方面的,是以整理一份Android進階開發工程師面試集錦,對照這些問題進行複習,将會事半功倍。從基礎到中級在進階,從Android到java,記錄下來有需要的時候多複習複習,也希望能幫到有需要的你。
-
- Android部分
- 1、Activity生命周期?
- 2、Service生命周期?
- 3、Activity的啟動過程
- 4、Broadcast注冊方式與差別
- HttpClient與HttpUrlConnection的差別
- 6、java虛拟機和Dalvik虛拟機的差別
- 7、程序保活(不死程序)
- 8、講解一下Context
- 9、了解Activity,View,Window三者關系
- 10、四種LaunchMode及其使用場景
- 11、View的繪制流程
- 12、View,ViewGroup事件分發
- 13、儲存Activity狀态
- 14、Android中的幾種動畫
- 15、Android中跨程序通訊的幾種方式
- 16、AIDL了解
- 17、Handler的原理
- 18、Binder機制原理
- 19、熱修複的原理
- 20、Android記憶體洩露及管理
- 記憶體洩露原因:
- 一、Handler 引起的記憶體洩漏。
- 二、單例模式引起的記憶體洩漏。
- 三、非靜态内部類建立靜态執行個體引起的記憶體洩漏。
- 四、非靜态匿名内部類引起的記憶體洩漏。
- 五、注冊/反注冊未成對使用引起的記憶體洩漏。
- 六、資源對象沒有關閉引起的記憶體洩漏。
- 七、集合對象沒有及時清理引起的記憶體洩漏。
- 21、Fragment與Fragment、Activity通信的方式
- 22、Android UI适配
- 23、app優化
- 24、圖檔優化
- 25、HybridApp WebView和JS互動
- 26、JAVA GC原理
- 27、ANR
- 解決方式:
- 28、單例模式
- 29、RxJava
- 30、MVC,MVP,MVVM
- 一、MVC(Model-View-Controller)
- 二、MVP(Model-View-Presenter)
- 三、MVVM(Model-View-ViewModel)
- 31、手寫算法(選擇冒泡必須要會)
- *選擇法排序
- 冒泡排序
- 二分查詢
- 32、JNI
- 33、RecyclerView和ListView的差別
- 34、Universal-ImageLoader,Picasso,Fresco,Glide對比
- Fresco
- Universal-ImageLoader
- Picasso
- Glide
- 42、Xutils, OKhttp, Volley, Retrofit對比
- Java部分
- 1、線程中sleep和wait的差別
- 2、Thread中的start()和run()方法有什麼差別
- 3、關鍵字final和static是怎麼使用的。
-
- final:
- static:
-
- 4、String,StringBuffer,StringBuilder差別
- 5、Java中重載和重寫的差別:
- 6、Http https差別
- 7、Http位于TCP/IP模型中的第幾層?為什麼說Http是可靠的資料傳輸協定?
- 8、HTTP連結的特點
- 9、TCP和UDP的差別
- 10、Socket建立網絡連接配接的步驟
- 11、Tcp/IP三次握手,四次揮手
- Android部分
Android部分
1、Activity生命周期?
onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()
2、Service生命周期?
service 啟動方式有兩種,一種是通過startService()方式進行啟動,另一種是通過bindService()方式進行啟動。不同的啟動方式他們的生命周期是不一樣.
- 通過startService()這種方式啟動的service,生命周期是這樣:調用startService() → onCreate()→ onStartCommand()→ onDestroy()。這種方式啟動的話,需要注意一下幾個問題:
- 當我們通過startService被調用以後,多次在調用startService(),onCreate()方法也隻會被調用一次,而onStartConmon()會被多次調用當我們調用stopService()的時候,onDestroy()就會被調用,進而銷毀服務。
- 當我們通過startService啟動時候,通過intent傳值,在onStartCommand()方法中擷取值的時候,一定要先判斷intent是否為null。
- 通過bindService()方式進行綁定,這種方式綁定service,生命周期走法:bindService→onCreate()→onBind()→unBind()→onDestroy() ,bindService這種方式進行啟動service好處是更加便利activity中操作service,比如加入service中有幾個方法,a,b ,如果要在activity中調用,在需要在activity擷取ServiceConnection對象,通過ServiceConnection來擷取service中内部類的類對象,然後通過這個類對象就可以調用類中的方法,當然這個類需要繼承Binder對象
3、Activity的啟動過程
這個題不是問的生命周期,是以不要隻簡單的回答下生命周期就沒了。
app啟動的過程有兩種情況,第一種是從桌面launcher上點選相應的應用圖示,第二種是在activity中通過調用startActivity來啟動一個新的activity。
我們建立一個新的項目,預設的根activity都是MainActivity,而所有的activity都是儲存在堆棧中的,我們啟動一個新的activity就會放在上一個activity上面,而我們從桌面點選應用圖示的時候,由于launcher本身也是一個應用,當我們點選圖示的時候,系統就會調用startActivitySately(),一般情況下,我們所啟動的activity的相關資訊都會儲存在intent中,比如action,category等等。
我們在安裝這個應用的時候,系統也會啟動一個PackaManagerService的管理服務,這個管理服務會對AndroidManifest.xml檔案進行解析,進而得到應用程式中的相關資訊,比如service,activity,Broadcast等等,然後獲得相關元件的資訊。當我們點選應用圖示的時候,就會調用startActivitySately()方法,而這個方法内部則是調用startActivty(),而startActivity()方法最終還是會調用startActivityForResult()這個方法。而在startActivityForResult()這個方法。
因為startActivityForResult()方法是有傳回結果的,是以系統就直接給一個**-1**,就表示不需要結果傳回了。而startActivityForResult()這個方法實際是通過Instrumentation類中的execStartActivity()方法來啟動activity,Instrumentation這個類主要作用就是監控程式和系統之間的互動。而在這個execStartActivity()方法中會擷取ActivityManagerService的代理對象,通過這個代理對象進行啟動activity。
啟動會就會調用一個checkStartActivityResult()方法,如果說沒有在配置清單中配置有這個元件,就會在這個方法中抛出異常了。當然最後是調用的是Application.scheduleLaunchActivity()進行啟動activity,而這個方法中通過擷取得到一個ActivityClientRecord對象,而這個ActivityClientRecord通過handler來進行消息的發送,系統内部會将每一個activity元件使用ActivityClientRecord對象來進行描述,而ActivityClientRecord對象中儲存有一個LoaderApk對象,通過這個對象調用handleLaunchActivity來啟動activity元件,而頁面的生命周期方法也就是在這個方法中進行調用。
4、Broadcast注冊方式與差別
Broadcast廣播,注冊方式主要有兩種.
第一種是靜态注冊,也可稱為常駐型廣播,這種廣播需要在Androidmanifest.xml中進行注冊,這中方式注冊的廣播,不受頁面生命周期的影響,即使退出了頁面,也可以收到廣播這種廣播一般用于想開機自啟動啊等等,由于這種注冊的方式的廣播是常駐型廣播,是以會占用CPU的資源。
第二種是動态注冊,而動态注冊的話,是在代碼中注冊的,這種注冊方式也叫非常駐型廣播,收到生命周期的影響,退出頁面後,就不會收到廣播,我們通常運用在更新UI方面。這種注冊方式優先級較高。最後需要解綁,否會會記憶體洩露
廣播是分為有序廣播和無序廣播。
HttpClient與HttpUrlConnection的差別
首先HttpClient和HttpUrlConnection 這兩種方式都支援Https協定,都是以流的形式進行上傳或者下載下傳資料,也可以說是以流的形式進行資料的傳輸,還有ipv6,以及連接配接池等功能。HttpClient這個擁有非常多的API,是以如果想要進行擴充的話,并且不破壞它的相容性的話,很難進行擴充,也就是這個原因,Google在Android6.0的時候,直接就棄用了這個HttpClient.
而HttpUrlConnection相對來說就是比較輕量級了,API比較少,容易擴充,并且能夠滿足Android大部分的資料傳輸。比較經典的一個架構volley,在2.3版本以前都是使用HttpClient,在2.3以後就使用了HttpUrlConnection。
6、java虛拟機和Dalvik虛拟機的差別
Java虛拟機:
1、java虛拟機基于棧。 基于棧的機器必須使用指令來載入和操作棧上資料,所需指令更多更多。
2、java虛拟機運作的是java位元組碼。(java類會被編譯成一個或多個位元組碼.class檔案)
Dalvik虛拟機:
- 1、dalvik虛拟機是基于寄存器的
- 2、Dalvik運作的是自定義的.dex位元組碼格式。(java類被編譯成.class檔案後,會通過一個dx工具将所有的.class檔案轉換成一個.dex檔案,然後dalvik虛拟機會從其中讀取指令和資料
- 3、常量池已被修改為隻使用32位的索引,以 簡化解釋器。
- 4、一個應用,一個虛拟機執行個體,一個程序(所有android應用的程序都是對應一個linux程序,都運作在自己的沙盒中,不同的應用在不同的程序中運作。每個android dalvik應用程式都被賦予了一個獨立的linux PID(app_*))。
7、程序保活(不死程序)
說到程序保活,首先得知道程序的優先級,程序分為下面幾種,優先級也是從高到低
- 前台程序 (Foreground process)
- 可見程序 (Visible process)
- 服務程序 (Service process)
- 背景程序 (Background process)
- 空程序 (Empty process)
目前業界的Android程序保活手段主要分為 黑、白、灰 三種,其大緻的實作思路如下:
- 黑色保活 :不同的app程序,用廣播互相喚醒(包括利用系統提供的廣播進行喚醒)
- 白色保活 :啟動前台Service
- 灰色保活 :利用系統的漏洞啟動前台Service
所謂黑色保活,就是利用不同的app程序使用廣播來進行互相喚醒。舉個3個比較常見的場景:
場景1 :開機,網絡切換、拍照、拍視訊時候,利用系統産生的廣播喚醒app
場景2 :接入第三方SDK也會喚醒相應的app程序,如微信sdk會喚醒微信,支付寶sdk會喚醒支付寶。由此發散開去,就會直接觸發了下面的 場景3
場景3 :假如你手機裡裝了支付寶、淘寶、天貓、UC等阿裡系的app,那麼你打開任意一個阿裡系的app後,有可能就順便把其他阿裡系的app給喚醒了。(隻是拿阿裡打個比方,其實BAT系都差不多)
白色保活
白色保活手段非常簡單,就是調用系統api啟動一個前台的Service程序,這樣會在系統的通知欄生成一個Notification,用來讓使用者知道有這樣一個app在運作着,哪怕目前的app退到了背景。如LBE和QQ音樂這種
灰色保活
灰色保活,這種保活手段是應用範圍最廣泛。它是利用系統的漏洞來啟動一個前台的Service程序,與普通的啟動方式差別在于,它不會在系統通知欄處出現一個Notification,看起來就如同運作着一個背景Service程序一樣。這樣做帶來的好處就是,使用者無法察覺到你運作着一個前台程序(因為看不到Notification),但你的程序優先級又是高于普通背景程序的。那麼如何利用系統的漏洞呢,大緻的實作思路和代碼如下:
思路一:API < 18,啟動前台Service時直接傳入new Notification();
思路二:API >= 18,同時啟動兩個id相同的前台Service,然後再将後啟動的Service做stop處理
熟悉Android系統的童鞋都知道,系統出于體驗和性能上的考慮,app在退到背景時系統并不會真正的kill掉這個程序,而是将其緩存起來。打開的應用越多,背景緩存的程序也越多。在系統記憶體不足的情況下,系統開始依據自身的一套程序回收機制來判斷要kill掉哪些程序,以騰出記憶體來供給需要的app。這套殺程序回收記憶體的機制就叫 Low Memory Killer ,它是基于Linux核心的 OOM Killer(Out-Of-Memory killer)機制誕生。
- 程序的重要性,劃分5級:-
- 前台程序 (Foreground process)
- 可見程序 (Visible process)
- 服務程序 (Service process)
- 背景程序 (Background process)
- 空程序 (Empty process)
了解完 Low Memory Killer,再科普一下oom_adj。什麼是oom_adj?它是linux核心配置設定給每個系統程序的一個值,代表程序的優先級,程序回收機制就是根據這個優先級來決定是否進行回收。對于oom_adj的作用,你隻需要記住以下幾點即可:
程序的oom_adj越大,表示此程序優先級越低,越容易被殺回收;越小,表示程序優先級越高,越不容易被殺回收
普通app程序的oom_adj>=0,系統程序的oom_adj才可能<0
有些手機廠商把這些知名的app放入了自己的白名單中,保證了程序不死來提高使用者體驗(如微信、QQ、陌陌都在小米的白名單中)。如果從白名單中移除,他們終究還是和普通app一樣躲避不了被殺的命運,為了盡量避免被殺,還是老老實實去做好優化工作吧。
是以,程序保活的根本方案終究還是回到了性能優化上,程序永生不死終究是個徹頭徹尾的僞命題!
8、講解一下Context
Context是一個抽象基類。在翻譯為上下文,也可以了解為環境,是提供一些程式的運作環境基礎資訊。Context下有兩個子類,ContextWrapper是上下文功能的封裝類,而ContextImpl則是上下文功能的實作類。而ContextWrapper又有三個直接的子類, ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一個帶主題的封裝類,而它有一個直接子類就是Activity,是以Activity和Service以及Application的Context是不一樣的,隻有Activity需要主題,Service不需要主題。
Context一共有三種類型,分别是Application、Activity和Service。這三個類雖然分别各種承擔着不同的作用,但它們都屬于Context的一種,而它們具體Context的功能則是由ContextImpl類去實作的,是以在絕大多數場景下,Activity、Service和Application這三種類型的Context都是可以通用的。不過有幾種場景比較特殊,比如啟動Activity,還有彈出Dialog。出于安全原因的考慮,Android是不允許Activity或Dialog憑空出現的,一個Activity的啟動必須要建立在另一個Activity的基礎之上,也就是以此形成的傳回棧。而Dialog則必須在一個Activity上面彈出(除非是System Alert類型的Dialog),是以在這種場景下,我們隻能使用Activity類型的Context,否則将會出錯。
getApplicationContext()和getApplication()方法得到的對象都是同一個application對象,隻是對象的類型不一樣。
Context數量 = Activity數量 + Service數量 + 1 (1為Application)
9、了解Activity,View,Window三者關系
這個問題真的很不好回答。是以這裡借用一個算是比較恰當的比喻來形容下它們的關系吧。Activity像一個工匠(控制單元),Window像窗戶(承載模型),View像窗花(顯示視圖)LayoutInflater像剪刀,Xml配置像窗花圖紙。
- 1:Activity構造的時候會初始化一個Window,準确的說是PhoneWindow。
- 2:這個PhoneWindow有一個“ViewRoot”,這個“ViewRoot”是一個View或者說ViewGroup,是最初始的根視圖。
- 3:“ViewRoot”通過addView方法來一個個的添加View。比如TextView,Button等
- 4:這些View的事件監聽,是由WindowManagerService來接受消息,并且回調Activity函數。比如onClickListener,onKeyDown等。
10、四種LaunchMode及其使用場景
棧與隊列的差別:
- 隊列先進先出,棧先進後出
- 對插入和删除操作的”限定”。 棧是限定隻能在表的一端進行插入和删除操作的線性表。 隊列是限定隻能在表的一端進行插入和在另一端進行删除操作的線性表。
- 周遊資料速度不同
啟動模式-LaunchMode
- standard 模式
這是預設模式,每次激活Activity時都會建立Activity執行個體,并放入任務棧中。使用場景:大多數Activity。
- singleTop 模式
如果在任務的棧頂正好存在該Activity的執行個體,就重用該執行個體( 會調用執行個體的 onNewIntent() ),否則就會建立新的執行個體并放入棧頂,即使棧中已經存在該Activity的執行個體,隻要不在棧頂,都會建立新的執行個體。使用場景如新聞類或者閱讀類App的内容頁面。
- singleTask 模式
如果在棧中已經有該Activity的執行個體,就重用該執行個體(會調用執行個體的 onNewIntent() )。重用時,會讓該執行個體回到棧頂,是以在它上面的執行個體将會被移出棧。如果棧中不存在該執行個體,将會建立新的執行個體放入棧中。使用場景如浏覽器的主界面。不管從多少個應用啟動浏覽器,隻會啟動主界面一次,其餘情況都會走onNewIntent,并且會清空主界面上面的其他頁面。
- singleInstance 模式
在一個新棧中建立該Activity的執行個體,并讓多個應用共享該棧中的該Activity執行個體。一旦該模式的Activity執行個體已經存在于某個棧中,任何應用再激活該Activity時都會重用該棧中的執行個體( 會調用執行個體的 onNewIntent() )。其效果相當于多個應用共享一個應用,不管誰激活該 Activity 都會進入同一個應用中。使用場景如鬧鈴提醒,将鬧鈴提醒與鬧鈴設定分離。singleInstance不要用于中間頁面,如果用于中間頁面,跳轉會有問題,比如:A -> B (singleInstance) -> C,完全退出後,在此啟動,首先打開的是B。
11、View的繪制流程
自定義控件:
1、組合控件。這種自定義控件不需要我們自己繪制,而是使用原生控件組合成的新控件。如标題欄。
2、繼承原有的控件。這種自定義控件在原生控件提供的方法外,可以自己添加一些方法。如制作圓角,圓形圖檔。
3、完全自定義控件:這個View上所展現的内容全部都是我們自己繪制出來的。比如說制作水波紋進度條。
View的繪制流程:OnMeasure()——>OnLayout()——>OnDraw()
第一步:OnMeasure():測量視圖大小。從頂層父View到子View遞歸調用measure方法,measure方法又回調OnMeasure。
第二步:OnLayout():确定View位置,進行頁面布局。從頂層父View向子View的遞歸調用view.layout方法的過程,即父View根據上一步measure子View所得到的布局大小和布局參數,将子View放在合适的位置上。
第三步:OnDraw():繪制視圖。ViewRoot建立一個Canvas對象,然後調用OnDraw()。六個步驟:
①、繪制視圖的背景;
②、儲存畫布的圖層(Layer);
③、繪制View的内容;
④、繪制View子視圖,如果沒有就不用;
⑤、還原圖層(Layer);
⑥、繪制滾動條。
12、View,ViewGroup事件分發
- Touch事件分發中隻有兩個主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三個相關事件。View包含dispatchTouchEvent、onTouchEvent兩個相關事件。其中ViewGroup又繼承于View。
- ViewGroup和View組成了一個樹狀結構,根節點為Activity内部包含的一個ViwGroup。
- 觸摸事件由Action_Down、Action_Move、Aciton_UP組成,其中一次完整的觸摸事件中,Down和Up都隻有一個,Move有若幹個,可以為0個。
- 當Acitivty接收到Touch事件時,将周遊子View進行Down事件的分發。ViewGroup的周遊可以看成是遞歸的。分發的目的是為了找到真正要處理本次完整觸摸事件的View,這個View會在onTouchuEvent結果傳回true。
- .當某個子View傳回true時,會中止Down事件的分發,同時在ViewGroup中記錄該子View。接下去的Move和Up事件将由該子View直接進行處理。由于子View是儲存在ViewGroup中的,多層ViewGroup的節點結構時,上級ViewGroup儲存的會是真實處理事件的View所在的ViewGroup對象:如ViewGroup0-ViewGroup1-TextView的結構中,TextView傳回了true,它将被儲存在ViewGroup1中,而ViewGroup1也會傳回true,被儲存在ViewGroup0中。當Move和UP事件來時,會先從ViewGroup0傳遞至ViewGroup1,再由ViewGroup1傳遞至TextView。
- 當ViewGroup中所有子View都不捕獲Down事件時,将觸發ViewGroup自身的onTouch事件。觸發的方式是調用super.dispatchTouchEvent函數,即父類View的dispatchTouchEvent方法。在所有子View都不處理的情況下,觸發Acitivity的onTouchEvent方法。
- onInterceptTouchEvent有兩個作用:
- 攔截Down事件的分發。
- 中止Up和Move事件向目标View傳遞,使得目标View所在的ViewGroup捕獲Up和Move事件。
13、儲存Activity狀态
onSaveInstanceState(Bundle)會在activity轉入背景狀态之前被調用,也就是onStop()方法之前,onPause方法之後被調用
14、Android中的幾種動畫
幀動畫:指通過指定每一幀的圖檔和播放時間,有序的進行播放而形成動畫效果,比如想聽的律動條。
補間動畫:指通過指定View的初始狀态、變化時間、方式,通過一系列的算法去進行圖形變換,進而形成動畫效果,主要有Alpha、Scale、Translate、Rotate四種效果。注意:隻是在視圖層實作了動畫效果,并沒有真正改變View的屬性,比如滑動清單,改變标題欄的透明度。
屬性動畫:在Android3.0的時候才支援,通過不斷的改變View的屬性,不斷的重繪而形成動畫效果。相比于視圖動畫,View的屬性是真正改變了。比如view的旋轉,放大,縮小。
15、Android中跨程序通訊的幾種方式
Android 跨程序通信,像intent,contentProvider,廣播,service都可以跨程序通信。
intent:這種跨程序方式并不是通路記憶體的形式,它需要傳遞一個uri,比如說打電話。
contentProvider:這種形式,是使用資料共享的形式進行資料共享。
service:遠端服務,aidl
廣播
16、AIDL了解
AIDL: 每一個程序都有自己的Dalvik VM執行個體,都有自己的一塊獨立的記憶體,都在自己的記憶體上存儲自己的資料,執行着自己的操作,都在自己的那片狹小的空間裡過完自己的一生。而aidl就類似與兩個程序之間的橋梁,使得兩個程序之間可以進行資料的傳輸,跨程序通信有多種選擇,比如 BroadcastReceiver , Messenger 等,但是 BroadcastReceiver 占用的系統資源比較多,如果是頻繁的跨程序通信的話顯然是不可取的;Messenger 進行跨程序通信時請求隊列是同步進行的,無法并發執行。
Binde機制簡單了解:
在Android系統的Binder機制中,是有Client,Service,ServiceManager,Binder驅動程式組成的,其中Client,service,Service Manager運作在使用者空間,Binder驅動程式是運作在核心空間的。而Binder就是把這4種元件粘合在一塊的粘合劑,其中核心的元件就是Binder驅動程式,Service Manager提供輔助管理的功能,而Client和Service正是在Binder驅動程式和Service Manager提供的基礎設施上實作C/S 之間的通信。其中Binder驅動程式提供裝置檔案/dev/binder與使用者控件進行互動,
Client、Service,Service Manager通過open和ioctl檔案操作相應的方法與Binder驅動程式進行通信。而Client和Service之間的程序間通信是通過Binder驅動程式間接實作的。而Binder Manager是一個守護程序,用來管理Service,并向Client提供查詢Service接口的能力。
17、Handler的原理
Android中主線程是不能進行耗時操作的,子線程是不能進行更新UI的。是以就有了handler,它的作用就是實作線程之間的通信。
handler整個流程中,主要有四個對象,handler,Message,MessageQueue,Looper。當應用建立的時候,就會在主線程中建立handler對象
我們通過要傳送的消息儲存到Message中,handler通過調用sendMessage方法将Message發送到MessageQueue中,Looper對象就會不斷的調用loop()方法,不斷的從MessageQueue中取出Message交給handler進行處理。進而實作線程之間的通信。
18、Binder機制原理
在Android系統的Binder機制中,是有Client,Service,ServiceManager,Binder驅動程式組成的,其中Client,service,Service Manager運作在使用者空間,Binder驅動程式是運作在核心空間的。而Binder就是把這4種元件粘合在一塊的粘合劑,其中核心的元件就是Binder驅動程式,Service Manager提供輔助管理的功能,而Client和Service正是在Binder驅動程式和Service Manager提供的基礎設施上實作C/S 之間的通信。其中Binder驅動程式提供裝置檔案/dev/binder與使用者控件進行互動,
Client、Service,Service Manager通過open和ioctl檔案操作相應的方法與Binder驅動程式進行通信。而Client和Service之間的程序間通信是通過Binder驅動程式間接實作的。而Binder Manager是一個守護程序,用來管理Service,并向Client提供查詢Service接口的能力。
19、熱修複的原理
我們知道Java虛拟機 —— JVM 是加載類的class檔案的,而Android虛拟機——Dalvik/ART VM 是加載類的dex檔案,
而他們加載類的時候都需要ClassLoader,ClassLoader有一個子類BaseDexClassLoader,而BaseDexClassLoader下有一個
數組——DexPathList,是用來存放dex檔案,當BaseDexClassLoader通過調用findClass方法時,實際上就是周遊數組,
找到相應的dex檔案,找到,則直接将它return。而熱修複的解決方法就是将新的dex添加到該集合中,并且是在舊的dex的前面,
是以就會優先被取出來并且return傳回。
20、Android記憶體洩露及管理
- 記憶體溢出(OOM)和記憶體洩露(對象無法被回收)的差別。
- 引起記憶體洩露的原因
- 記憶體洩露檢測工具 ——→LeakCanary
記憶體溢出 out of memory:是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是記憶體溢出。記憶體溢出通俗的講就是記憶體不夠用。
記憶體洩露 memory leak:是指程式在申請記憶體後,無法釋放已申請的記憶體空間,一次記憶體洩露危害可以忽略,但記憶體洩露堆積後果很嚴重,無論多少記憶體,遲早會被占光
記憶體洩露原因:
一、Handler 引起的記憶體洩漏。
解決:将Handler聲明為靜态内部類,就不會持有外部類XXXActivity的引用,其生命周期就和外部類無關,
如果Handler裡面需要context的話,可以通過弱引用方式引用外部類
二、單例模式引起的記憶體洩漏。
解決:Context是ApplicationContext,由于ApplicationContext的生命周期是和app一緻的,不會導緻記憶體洩漏
三、非靜态内部類建立靜态執行個體引起的記憶體洩漏。
解決:把内部類修改為靜态的就可以避免記憶體洩漏了
四、非靜态匿名内部類引起的記憶體洩漏。
解決:将匿名内部類設定為靜态的。
五、注冊/反注冊未成對使用引起的記憶體洩漏。
注冊廣播接受器、EventBus等,記得解綁。
六、資源對象沒有關閉引起的記憶體洩漏。
在這些資源不使用的時候,記得調用相應的類似close()、destroy()、recycler()、release()等方法釋放。
七、集合對象沒有及時清理引起的記憶體洩漏。
通常會把一些對象裝入到集合中,當不使用的時候一定要記得及時清理集合,讓相關對象不再被引用。
21、Fragment與Fragment、Activity通信的方式
- 1.直接在一個Fragment中調用另外一個Fragment中的方法
- 2.使用接口回調
- 3.使用廣播
- 4.Fragment直接調用Activity中的public方法
22、Android UI适配
字型使用sp,寬高使用dp,多使用match_parent,wrap_content,weight
圖檔資源,不同圖檔的的分辨率,放在相應的檔案夾下可使用百分比代替。
23、app優化
app優化:(工具:Hierarchy Viewer 分析布局 工具:TraceView 測試分析耗時的)
- App啟動優化
- 布局優化
- 響應優化
- 記憶體優化
- 電池使用優化
- 網絡優化
App啟動優化(針對冷啟動)
App啟動的方式有三種:
冷啟動:App沒有啟動過或App程序被killed, 系統中不存在該App程序, 此時啟動App即為冷啟動。
熱啟動:熱啟動意味着你的App程序隻是處于背景, 系統隻是将其從背景帶到前台, 展示給使用者。
介于冷啟動和熱啟動之間:一般來說在以下兩種情況下發生:
- (1)使用者back退出了App, 然後又啟動. App程序可能還在運作, 但是activity需要重建。
- (2)使用者退出App後, 系統可能由于記憶體原因将App殺死, 程序和activity都需要重新開機, 但是可以在onCreate中将被動殺死鎖儲存的狀态(saved instance state)恢複。
優化:
Application的onCreate(特别是第三方SDK初始化),首屏Activity的渲染都不要進行耗時操作,如果有,就可以放到子線程或者IntentService中
布局優化
盡量不要過于複雜的嵌套。可以使用ConstrainLayout解決複雜的嵌套布局
響應優化
Android系統每隔16ms會發出VSYNC信号重繪我們的界面(Activity)。
頁面卡頓的原因:
- (1)過于複雜的布局.
- (2)UI線程的複雜運算
-
(3)頻繁的GC,導緻頻繁GC有兩個原因:
1、記憶體抖動, 即大量的對象被建立又在短時間内馬上被釋放.
2、瞬間産生大量的對象會嚴重占用記憶體區域。
記憶體優化:參考記憶體洩露和記憶體溢出部分
電池使用優化(使用工具:Batterystats & bugreport)
- (1)優化網絡請求
- (2)定位中使用GPS, 請記得及時關閉
網絡優化(網絡連接配接對使用者的影響:流量,電量,使用者等待)可在Android studio下方Mirror工具檢測
- API設計:App與Server之間的API設計要考慮網絡請求的頻次, 資源的狀态等. 以便App可以以較少的請求來完成業務需求和界面的展示.
- Gzip壓縮:使用Gzip來壓縮request和response, 減少傳輸資料量, 進而減少流量消耗.
- 圖檔的Size:可以在擷取圖檔時告知伺服器需要的圖檔的寬高, 以便伺服器給出合适的圖檔, 避免浪費.
- 網絡緩存:适當的緩存, 既可以讓我們的應用看起來更快, 也能避免一些不必要的流量消耗.
24、圖檔優化
- 對圖檔本身進行操作。盡量不要使用setImageBitmap、setImageResource、BitmapFactory.decodeResource來設定一張大圖,因為這些方法在完成decode後,最終都是通過java層的createBitmap來完成的,需要消耗更多記憶體.
- 圖檔進行縮放的比例,SDK中建議其值是2的指數值,值越大會導緻圖檔不清晰。
- 不用的圖檔記得調用圖檔的recycle()方法
25、HybridApp WebView和JS互動
Android與JS通過WebView互相調用方法,實際上是:
Android去調用JS的代碼
- 通過WebView的loadUrl(),使用該方法比較簡潔,友善。但是效率比較低,擷取傳回值比較困難。
- .通過WebView的evaluateJavascript(),該方法效率高,但是4.4以上的版本才支援,4.4以下版本不支援。是以建議兩者混合使用。
JS去調用Android的代碼
-
通過WebView的addJavascriptInterface()進行對象映射 ,該方法使用簡單,僅将Android對象和JS對象映射即可,但是存在比較大的漏洞。
漏洞産生原因是:當JS拿到Android這個對象後,就可以調用這個Android對象中所有的方法,包括系統類(java.lang.Runtime 類),進而進行任意代碼執行。
解決方式:
- Google 在Android 4.2 版本中規定對被調用的函數以 @JavascriptInterface進行注解進而避免漏洞攻擊。
- 在Android 4.2版本之前采用攔截prompt()進行漏洞修複。
- 通過 WebViewClient 的shouldOverrideUrlLoading ()方法回調攔截 url 。這種方式的優點:不存在方式1的漏洞;缺點:JS擷取Android方法的傳回值複雜。(ios主要用的是這個方式)
- Android通過 WebViewClient 的回調方法shouldOverrideUrlLoading ()攔截 url
- 解析該 url 的協定
- 如果檢測到是預先約定好的協定,就調用相應方法
-
通過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調攔截JS對話框alert()、confirm()、prompt() 消息
這種方式的優點:不存在方式1的漏洞;缺點:JS擷取Android方法的傳回值複雜。
26、JAVA GC原理
垃圾收集算法的核心思想是:對虛拟機可用記憶體空間,即堆空間中的對象進行識别,如果對象正在被引用,那麼稱其為存活對象,反之,如果對象不再被引用,則為垃圾對象,可以回收其占據的空間,用于再配置設定。垃圾收集算法的選擇和垃圾收集系統參數的合理調節直接影響着系統性能。
27、ANR
ANR全名Application Not Responding, 也就是”應用無響應”. 當操作在一段時間内系統無法處理時, 系統層面會彈出上圖那樣的ANR對話框.
産生原因:
- 5s内無法響應使用者輸入事件(例如鍵盤輸入, 觸摸螢幕等).
- BroadcastReceiver在10s内無法結束
- Service 20s内無法結束(低機率)
解決方式:
- 不要在主線程中做耗時的操作,而應放在子線程中來實作。如onCreate()和onResume()裡盡可能少的去做建立操作。
- 應用程式應該避免在BroadcastReceiver裡做耗時的操作或計算。
- 避免在Intent Receiver裡啟動一個Activity,因為它會建立一個新的畫面,并從目前使用者正在運作的程式上搶奪焦點。
- service是運作在主線程的,是以在service中做耗時操作,必須要放在子線程中。
28、單例模式
單例模式:分為惡漢式和懶漢式
餓漢式:
public class Singleton
{
private static Singleton instance = new Singleton();
public static Singleton getInstance()
{
return instance ;
}
}
懶漢式:
public class Singleton02
{
private static Singleton02 instance;
public static Singleton02 getInstance()
{
if (instance == null)
{
synchronized (Singleton02.class)
{
if (instance == null)
{
instance = new Singleton02();
}
}
}
return instance;
}
}
29、RxJava
這個可以多去看一下相關的文章和部落格,然後自己動手寫一下
30、MVC,MVP,MVVM
一、MVC(Model-View-Controller)
MVC是比較直覺的架構模式,使用者操作->View(負責接收使用者的輸入操作)->Controller(業務邏輯處理)->Model(資料持久化)->View(将結果回報給View)。
MVC使用非常廣泛,比如JavaEE中的SSH架構(Struts/Spring/Hibernate),Struts(View, STL)-Spring(Controller, Ioc、Spring MVC)-Hibernate(Model, ORM)以及ASP.NET中的ASP.NET MVC架構,xxx.cshtml-xxxcontroller-xxxmodel。(實際上後端開發過程中是v-c-m-c-v,v和m并沒有關系,下圖僅代表經典的mvc模型)
二、MVP(Model-View-Presenter)
MVP是把MVC中的Controller換成了Presenter(呈現),目的就是為了完全切斷View跟Model之間的聯系,由Presenter充當橋梁,做到View-Model之間通信的完全隔離。
.NET程式員熟知的ASP.NET webform、winform基于事件驅動的開發技術就是使用的MVP模式。控件組成的頁面充當View,實體資料庫操作充當Model,而View和Model之間的控件資料綁定操作則屬于Presenter。控件事件的處理可以通過自定義的IView接口實作,而View和IView都将對Presenter負責。
三、MVVM(Model-View-ViewModel)
如果說MVP是對MVC的進一步改進,那麼MVVM則是思想的完全變革。它是将“資料模型資料雙向綁定”的思想作為核心,是以在View和Model之間沒有聯系,通過ViewModel進行互動,而且Model和ViewModel之間的互動是雙向的,是以視圖的資料的變化會同時修改資料源,而資料源資料的變化也會立即反應到View上。
這方面典型的應用有.NET的WPF,js架構Knockout、AngularJS等。
31、手寫算法(選擇冒泡必須要會)
*選擇法排序
選擇法排序的基本思想是:首先從待排序的n個數中找出最小的一個與array[0]對換;再将array [1]到array [n]中的最小數與array [1]對換,依此類推。每比較一輪,找出待排序數中最小的一個數進行交換,共進行n-1次交換便可完成排序。選擇法排序每執行一次外循環隻進行一次數組元素的交換,可使交換的次數大大減少。
代碼實作:
public class SelectSort{
public static void main(String [] args){
int a[] = {1, 2, 3, 56, 45, 22, 22, 26, 89, 99, 100};
System.out.println("排序前:");
for (int i = 0; i < a.length; ++ i){
System.out.print(a[i] + " ");
}
selectSort(a);
System.out.println("\n");
System.out.println("排序後:");
for (int i = 0; i < a.length; ++ i){
System.out.print(a[i] + " ");
}
}
public static void selectSort(int a[]){
int min = 0;
int temp = 0;
for (int i = 0; i < a.length - 1; ++ i){
min = i;
for (int j = i + 1; j < a.length; ++ j){
if (a[min] > a[j]){
min = j;
}
}
if (min != i){
temp = a[min];
a[min] = a[i];
a[i] = temp;
}
}
}
}
冒泡排序
冒泡排序的關鍵點是從後向前對相鄰的兩個數組元素進行比較,若後面元素的值小于前面元素的值,則将這兩個元素交換位置,否則不進行交換。依次進行下去,第一趟排序可将數組中值最小的元素移至下标為0的位置。對于有n個元素的數組,循環執行n-1趟掃描便可完成排序。(當然,也可以從前向後對相鄰的兩個數組元素進行比較,但此時應注意将大數向後移,與小者前移的冒泡法相對應,可将這種大者後移的排序稱為下沉法)。
代碼實作:
public class BubbleSort{
public static void main(String[] args){
int a[] = {1, 23, 45, 6, 0, 99, 100, 89, 34, 56};
System.out.println("排序前:");
for (int i = 0; i < a.length; ++ i)
System.out.print(a[i] + " ");
bubbleSort(a);
System.out.println();
System.out.println("排序後:");
for (int i = 0; i < a.length; ++ i)
System.out.print(a[i] + " ");
}
public static void bubbleSort(int a[]){
int temp = 0;
for (int i = 0; i < a.length - 1; ++ i){
for (int j = i; j < a.length; ++ j){
if (a[i] > a[j]){
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
}
二分查詢
二分查找是在一個有序表(資料是按其值由小到大或由大到小依次存放的,這裡我們以值由小到大排列為例)中,每次都與中間的那個元素比較,若相等則查找成功;否則,調整查找範圍,若中間那個元素的值小于待查值,則在表的後一半中查找;若中間那個元素的值大于待查值,則在表的前一半中查找;如此循環,每次隻與一半中的一個元素比較,可使查找效率大大提高。
import java.util.*;
public class FindSearch{
public static void main(String [] args){
int a[] = {2, 4, 7, 18, 25, 34, 56, 68, 89};
System.out.println("列印原始資料:");
for (int i = 0; i < a.length; ++ i){
System.out.print(a[i] + " ");
}
System.out.println();
System.out.println("請輸入要查找的整數:");
Scanner scan = new Scanner(System.in);
int num = scan.nextInt();
int pos = 0;
pos = binaryFind(a, num);
if (-1 != pos)
System.out.println("所查整數在數組中的位置下标是:" + pos);
else
System.out.println("沒找到待查資料!");
}
public static int binaryFind(int a[],int num){
int low, mid, high;
low = 0;//low是第一個數組元素的下标
high = a.length - 1;//high是最後一個數組元素的下标
mid = (low + high) / 2;//mid是中間那個數組元素的下标
while (low <= high){
if (num == a[mid]){
return mid;
}else if (num > a[mid]){
low = mid + 1;//要找的數可能在數組的後半部分中
mid = (low + high) / 2;
}else{
high = mid - 1;//要找的數可能在數組的前半部分中
mid = (low + high) / 2;
}
}
//mid是數組元素下标,若為-1則表示不存在要查的元素
if (mid != ((low + high) / 2))
return mid;
else
return -1;
}
}
32、JNI
- 安裝和下載下傳Cygwin,下載下傳 Android NDK
- 在ndk項目中JNI接口的設計
- 使用C/C++實作本地方法
- JNI生成動态連結庫.so檔案
- 将動态連結庫複制到java工程,在java工程中調用,運作java工程即可
33、RecyclerView和ListView的差別
RecyclerView可以完成ListView,GridView的效果,還可以完成瀑布流的效果。同時還可以設定清單的滾動方向(垂直或者水準);
RecyclerView中view的複用不需要開發者自己寫代碼,系統已經幫封裝完成了。
RecyclerView可以進行局部重新整理。
RecyclerView提供了API來實作item的動畫效果。
在性能上:
如果需要頻繁的重新整理資料,需要添加動畫,則RecyclerView有較大的優勢。
如果隻是作為清單展示,則兩者差別并不是很大。
34、Universal-ImageLoader,Picasso,Fresco,Glide對比
Fresco
resco是 Facebook 推出的開源圖檔緩存工具,主要特點包括:兩個記憶體緩存加上 Native 緩存構成了三級緩存,
優點:
- 圖檔存儲在安卓系統的匿名共享記憶體, 而不是虛拟機的堆記憶體中, 圖檔的中間緩沖資料也存放在本地堆記憶體, 是以, 應用程式有更多的記憶體使用, 不會因為圖檔加載而導緻oom, 同時也減少垃圾回收器頻繁調用回收 Bitmap 導緻的界面卡頓, 性能更高。
- 漸進式加載 JPEG 圖檔, 支援圖檔從模糊到清晰加載。
- 圖檔可以以任意的中心點顯示在 ImageView, 而不僅僅是圖檔的中心。
- PEG 圖檔改變大小也是在 native 進行的, 不是在虛拟機的堆記憶體, 同樣減少 OOM。
- 很好的支援 GIF 圖檔的顯示。
缺點:
- 架構較大, 影響 Apk 體積
- 使用較繁瑣
Universal-ImageLoader
Universal-ImageLoader:(估計由于HttpClient被Google放棄,作者就放棄維護這個架構)
優點:
- 支援下載下傳進度監聽
- 可以在 View 滾動中暫停圖檔加載,通過 PauseOnScrollListener 接口可以在 View 滾動中暫停圖檔加載。
- 預設實作多種記憶體緩存算法 這幾個圖檔緩存都可以配置緩存算法,不過 ImageLoader 預設實作了較多緩存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先進先删除、時間最長先删除等。
- 支援本地緩存檔案名規則定義
Picasso
優點
- 自帶統計監控功能。支援圖檔緩存使用的監控,包括緩存命中率、已使用記憶體大小、節省的流量等。
- 支援優先級處理。每次任務排程前會選擇優先級高的任務,比如 App 頁面中 Banner 的優先級高于 Icon 時就很适用。
- 支援延遲到圖檔尺寸計算完成加載
- 支援飛行模式、并發線程數根據網絡類型而變。 手機切換到飛行模式或網絡類型變換時會自動調整線程池最大并發數,比如 wifi 最大并發為 4,4g 為 3,3g 為 2。 這裡 Picasso 根據網絡類型來決定最大并發數,而不是 CPU 核數。
- “無”本地緩存。無”本地緩存,不是說沒有本地緩存,而是 Picasso 自己沒有實作,交給了 Square 的另外一個網絡庫 okhttp 去實作,這樣的好處是可以通過請求 Response Header 中的 Cache-Control 及 Expired 控制圖檔的過期時間。
Glide
優點
- 不僅僅可以進行圖檔緩存還可以緩存媒體檔案。Glide 不僅是一個圖檔緩存,它支援 Gif、WebP、縮略圖。甚至是 Video,是以更該當做一個媒體緩存。
- 支援優先級處理。
- 與 Activity/Fragment 生命周期一緻,支援 trimMemory。Glide 對每個 context 都保持一個 RequestManager,通過 FragmentTransaction 保持與 Activity/Fragment 生命周期一緻,并且有對應的 trimMemory 接口實作可供調用。
- 支援 okhttp、Volley。Glide 預設通過 UrlConnection 擷取資料,可以配合 okhttp 或是 Volley 使用。實際 ImageLoader、Picasso 也都支援 okhttp、Volley。
- 記憶體友好。Glide 的記憶體緩存有個 active 的設計,從記憶體緩存中取資料時,不像一般的實作用 get,而是用 remove,再将這個緩存資料放到一個 value 為軟引用的 activeResources map 中,并計數引用數,在圖檔加載完成後進行判斷,如果引用計數為空則回收掉。記憶體緩存更小圖檔,Glide 以 url、view_width、view_height、螢幕的分辨率等做為聯合 key,将處理後的圖檔緩存在記憶體緩存中,而不是原始圖檔以節省大小與 Activity/Fragment 生命周期一緻,支援 trimMemory。圖檔預設使用預設 RGB_565 而不是 ARGB_888,雖然清晰度差些,但圖檔更小,也可配置到 ARGB_888。
- Glide 可以通過 signature 或不使用本地緩存支援 url 過期
42、Xutils, OKhttp, Volley, Retrofit對比
Xutils:這個架構非常全面,可以進行網絡請求,可以進行圖檔加載處理,可以資料儲存,還可以對view進行注解,使用這個架構非常友善,但是缺點也是非常明顯的,使用這個項目,會導緻項目對這個架構依賴非常的嚴重,一旦這個架構出現問題,那麼對項目來說影響非常大的。
OKhttp:Android開發中是可以直接使用現成的api進行網絡請求的。就是使用HttpClient,HttpUrlConnection進行操作。okhttp針對Java和Android程式,封裝的一個高性能的http請求庫,支援同步,異步,而且okhttp又封裝了線程池,封裝了資料轉換,封裝了參數的使用,錯誤處理等。API使用起來更加的友善。但是我們在項目中使用的時候仍然需要自己在做一層封裝,這樣才能使用的更加的順手。
**Volley:**Volley是Google官方出的一套小而巧的異步請求庫,該架構封裝的擴充性很強,支援HttpClient、HttpUrlConnection, 甚至支援OkHttp,而且Volley裡面也封裝了ImageLoader,是以如果你願意你甚至不需要使用圖檔加載架構,不過這塊功能沒有一些專門的圖檔加載架構強大,對于簡單的需求可以使用,稍複雜點的需求還是需要用到專門的圖檔加載架構。Volley也有缺陷,比如不支援post大資料,是以不适合上傳檔案。不過Volley設計的初衷本身也就是為頻繁的、資料量小的網絡請求而生。
**Retrofit:**Retrofit是Square公司出品的預設基于OkHttp封裝的一套RESTful網絡請求架構,RESTful是目前流行的一套api設計的風格, 并不是标準。Retrofit的封裝可以說是很強大,裡面涉及到一堆的設計模式,可以通過注解直接配置請求,可以使用不同的http用戶端,雖然預設是用http ,可以使用不同Json Converter 來序列化資料,同時提供對RxJava的支援,使用Retrofit + OkHttp + RxJava + Dagger2 可以說是目前比較潮的一套架構,但是需要有比較高的門檻。
Volley VS OkHttp
Volley的優勢在于封裝的更好,而使用OkHttp你需要有足夠的能力再進行一次封裝。而OkHttp的優勢在于性能更高,因為 OkHttp基于NIO和Okio ,是以性能上要比 Volley更快。IO 和 NIO這兩個都是Java中的概念,如果我從硬碟讀取資料,第一種方式就是程式一直等,資料讀完後才能繼續操作這種是最簡單的也叫阻塞式IO,還有一種是你讀你的,程式接着往下執行,等資料處理完你再來通知我,然後再處理回調。而第二種就是 NIO 的方式,非阻塞式, 是以NIO當然要比IO的性能要好了,而 Okio是 Square 公司基于IO和NIO基礎上做的一個更簡單、高效處理資料流的一個庫。理論上如果Volley和OkHttp對比的話,更傾向于使用 Volley,因為Volley内部同樣支援使用OkHttp,這點OkHttp的性能優勢就沒了, 而且 Volley 本身封裝的也更易用,擴充性更好些。
OkHttp VS Retrofit
毫無疑問,Retrofit 預設是基于 OkHttp 而做的封裝,這點來說沒有可比性,肯定首選 Retrofit。
Volley VS Retrofit
這兩個庫都做了不錯的封裝,但Retrofit解耦的更徹底,尤其Retrofit2.0出來,Jake對之前1.0設計不合理的地方做了大量重構, 職責更細分,而且Retrofit預設使用OkHttp,性能上也要比Volley占優勢,再有如果你的項目如果采用了RxJava ,那更該使用 Retrofit 。是以這兩個庫相比,Retrofit更有優勢,在能掌握兩個架構的前提下該優先使用 Retrofit。但是Retrofit門檻要比Volley稍高些,要了解他的原理,各種用法,想徹底搞明白還是需要花些功夫的,如果你對它一知半解,那還是建議在商業項目使用Volley吧。
Java部分
1、線程中sleep和wait的差別
- 這兩個方法來自不同的類,sleep是來自Thread,wait是來自Object;
- sleep方法沒有釋放鎖,而wait方法釋放了鎖。
- wait,notify,notifyAll隻能在同步控制方法或者同步控制塊裡面使用,而sleep可以在任何地方使用。
2、Thread中的start()和run()方法有什麼差別
start()方法是用來啟動新建立的線程,而start()内部調用了run()方法,這和直接調用run()方法是不一樣的,如果直接調用run()方法,則和普通的方法沒有什麼差別。
3、關鍵字final和static是怎麼使用的。
final:
- final變量即為常量,隻能指派一次。
- final方法不能被子類重寫。
- final類不能被繼承。
static:
-
static變量:對于靜态變量在記憶體中隻有一個拷貝(節省記憶體),JVM隻為靜态配置設定一次記憶體,
在加載類的過程中完成靜态變量的記憶體配置設定,可用類名直接通路(友善),當然也可以通過對象來通路(但是這是不推薦的)。
-
static代碼塊
static代碼塊是類加載時,初始化自動執行的。
-
static方法
static方法可以直接通過類名調用,任何的執行個體也都可以調用,是以static方法中不能用this和super關鍵字,
不能直接通路所屬類的執行個體變量和執行個體方法(就是不帶static的成員變量和成員成員方法),隻能通路所屬類的靜态成員變量和成員方法。
4、String,StringBuffer,StringBuilder差別
- 1、三者在執行速度上:StringBuilder > StringBuffer > String (由于String是常量,不可改變,拼接時會重新建立新的對象)。
- 2、StringBuffer是線程安全的,StringBuilder是線程不安全的。(由于StringBuffer有緩沖區)
5、Java中重載和重寫的差別:
1、重載:一個類中可以有多個相同方法名的,但是參數類型和個數都不一樣。這是重載。
2、重寫:子類繼承父類,則子類可以通過實作父類中的方法,進而新的方法把父類舊的方法覆寫。
6、Http https差別
- https協定需要到ca申請證書,一般免費證書較少,因而需要一定費用。
- http是超文本傳輸協定,資訊是明文傳輸,https則是具有安全性的ssl加密傳輸協定。
- http和https使用的是完全不同的連接配接方式,用的端口也不一樣,前者是80,後者是443。
- http的連接配接很簡單,是無狀态的;HTTPS協定是由SSL+HTTP協定建構的可進行加密傳輸、身份認證的網絡協定,比http協定安全。
https實作原理:
- 客戶使用https的URL通路Web伺服器,要求與Web伺服器建立SSL連接配接。
- Web伺服器收到用戶端請求後,會将網站的證書資訊(證書中包含公鑰)傳送一份給用戶端。
- 用戶端的浏覽器與Web伺服器開始協商SSL連接配接的安全等級,也就是資訊加密的等級。
- 用戶端的浏覽器根據雙方同意的安全等級,建立會話密鑰,然後利用網站的公鑰将會話密鑰加密,并傳送給網站。
- Web伺服器利用自己的私鑰解密出會話密鑰。
- Web伺服器利用會話密鑰加密與用戶端之間的通信。
7、Http位于TCP/IP模型中的第幾層?為什麼說Http是可靠的資料傳輸協定?
tcp/ip的五層模型:
從下到上:實體層->資料鍊路層->網絡層->傳輸層->應用層
其中tcp/ip位于模型中的網絡層,處于同一層的還有ICMP(網絡控制資訊協定)。http位于模型中的應用層
由于tcp/ip是面向連接配接的可靠協定,而http是在傳輸層基于tcp/ip協定的,是以說http是可靠的資料傳輸協定。
8、HTTP連結的特點
HTTP連接配接最顯著的特點是用戶端發送的每次請求都需要伺服器回送響應,在請求結束後,會主動釋放連接配接。
從建立連接配接到關閉連接配接的過程稱為“一次連接配接”。
9、TCP和UDP的差別
tcp是面向連接配接的,由于tcp連接配接需要三次握手,是以能夠最低限度的降低風險,保證連接配接的可靠性。
udp 不是面向連接配接的,udp建立連接配接前不需要與對象建立連接配接,無論是發送還是接收,都沒有發送确認信号。是以說udp是不可靠的。
由于udp不需要進行确認連接配接,使得UDP的開銷更小,傳輸速率更高,是以實時行更好。
10、Socket建立網絡連接配接的步驟
建立Socket連接配接至少需要一對套接字,其中一個運作與用戶端—ClientSocket,一個運作于服務端—ServiceSocket
- 伺服器監聽:伺服器端套接字并不定位具體的用戶端套接字,而是處于等待連接配接的狀态,實時監控網絡狀态,等待用戶端的連接配接請求。
- 用戶端請求:指用戶端的套接字提出連接配接請求,要連接配接的目标是伺服器端的套接字。注意:用戶端的套接字必須描述他要連接配接的伺服器的套接字,指出伺服器套接字的位址和端口号,然後就像伺服器端套接字提出連接配接請求。
- 連接配接确認:當伺服器端套接字監聽到用戶端套接字的連接配接請求時,就響應用戶端套接字的請求,建立一個新的線程,把伺服器端套接字的描述發給用戶端,一旦用戶端确認了此描述,雙方就正式建立連接配接。而服務端套接字則繼續處于監聽狀态,繼續接收其他用戶端套接字的連接配接請求。
11、Tcp/IP三次握手,四次揮手
【問題1】為什麼連接配接的時候是三次握手,關閉的時候卻是四次握手?
答:因為當Server端收到Client端的SYN連接配接請求封包後,可以直接發送SYN+ACK封包。其中ACK封包是用來應答的,SYN封包是用來同步的。但是關閉連接配接時,當Server端收到FIN封包時,很可能并不會立即關閉SOCKET,是以隻能先回複一個ACK封包,告訴Client端,”你發的FIN封包我收到了”。隻有等到我Server端所有的封包都發送完了,我才能發送FIN封包,是以不能一起發送。故需要四步握手。
【問題2】為什麼TIME_WAIT狀态需要經過2MSL(最大封包段生存時間)才能傳回到CLOSE狀态?
答:雖然按道理,四個封包都發送完畢,我們可以直接進入CLOSE狀态了,但是我們必須假象網絡是不可靠的,有可以最後一個ACK丢失。是以TIME_WAIT狀态就是用來重發可能丢失的ACK封包。在Client發送出最後的ACK回複,但該ACK可能丢失。Server如果沒有收到ACK,将不斷重複發送FIN片段。是以Client不能立即關閉,它必須确認Server接收到了該ACK。Client會在發送出ACK之後進入到TIME_WAIT狀态。Client會設定一個計時器,等待2MSL的時間。如果在該時間内再次收到FIN,那麼Client會重發ACK并再次等待2MSL。所謂的2MSL是兩倍的MSL(Maximum Segment Lifetime)。MSL指一個片段在網絡中最大的存活時間,2MSL就是一個發送和一個回複所需的最大時間。如果直到2MSL,Client都沒有再次收到FIN,那麼Client推斷ACK已經被成功接收,則結束TCP連接配接。
【問題3】為什麼不能用兩次握手進行連接配接?
答:3次握手完成兩個重要的功能,既要雙方做好發送資料的準備工作(雙方都知道彼此已準備好),也要允許雙方就初始序列号進行協商,這個序列号在握手過程中被發送和确認。
現在把三次握手改成僅需要兩次握手,死鎖是可能發生的。作為例子,考慮計算機S和C之間的通信,假定C給S發送一個連接配接請求分組,S收到了這個分組,并發 送了确認應答分組。按照兩次握手的協定,S認為連接配接已經成功地建立了,可以開始發送資料分組。可是,C在S的應答分組在傳輸中被丢失的情況下,将不知道S 是否已準備好,不知道S建立什麼樣的序列号,C甚至懷疑S是否收到自己的連接配接請求分組。在這種情況下,C認為連接配接還未建立成功,将忽略S發來的任何資料分 組,隻等待連接配接确認應答分組。而S在發出的分組逾時後,重複發送同樣的分組。這樣就形成了死鎖。
【問題4】如果已經建立了連接配接,但是用戶端突然出現故障了怎麼辦?
TCP還設有一個保活計時器,顯然,用戶端如果出現故障,伺服器不能一直等下去,白白浪費資源。伺服器每收到一次用戶端的請求後都會重新複位這個計時器,時間通常是設定為2小時,若兩小時還沒有收到用戶端的任何資料,伺服器就會發送一個探測封包段,以後每隔75分鐘發送一次。若一連發送10個探測封包仍然沒反應,伺服器就認為用戶端出了故障,接着就關閉連接配接。
最後
在這裡我也分享一份由幾位大佬一起收錄整理的 Flutter進階資料以及Android學習PDF+架構視訊+面試文檔+源碼筆記 ,并且還有 進階架構技術進階腦圖、Android開發面試專題資料,進階進階架構資料……
這些都是我閑暇時還會反複翻閱的精品資料。可以有效的幫助大家掌握知識、了解原理。當然你也可以拿去查漏補缺,提升自身的競争力。
如果你有需要的話,可以前往 點此處免費擷取 。