安卓面試題整理

知乎上一篇文章

1)JAVA基礎

1.java基本數據類型有哪些,int, long佔幾個字節

    四類八種基本數據類型:

數值型 整型(byte-1,short-2,int-4,long-8) 浮點型(float-4, double-8)
字符型 char
布爾型 boolean

2.== 和 equals有什麼區別

     ==判斷基本數據類型是判斷值是否相等,判斷引用類型是判斷地址是否指向同一個對象

     equals在Object類裏面和==一樣,重寫後可以判斷內容是否相同

3.hashcode 和 equals作用

equal()相等的兩個對象他們的hashCode()肯定相等,也就是用equal()對比是絕對可靠的。

      hashCode()相等的兩個對象他們的equal()不一定相等,也就是hashCode()不是絕對可靠的。

 所有對於需要大量並且快速的對比的話如果都用equal()去做顯然效率太低,所以解決方式是,
每當需要對比的時候,首先用hashCode()去對比,如果hashCode()不一樣,
則表示這兩個對象肯定不相等(也就是不必再用equal()去再對比了),
如果hashCode()相同,此時再對比他們的equal(),如果equal()也相同,
則表示這兩個對象是真的相同了,這樣既能大大提高了效率也保證了對比的絕對正確性!

4.new String創建了幾個對象

一個是字符串字面量"xyz"所對應的、駐留(intern)在一個全局共享的字符串常量池中的實例,
另一個是通過new String(String)創建並初始化的、內容與"xyz"相同的實例
String   s   =   new   String( "xyz "); 

首先在string字符串常量池內找,找到?不創建string對象,否則創建,   這樣就一個string對象
 
遇到new運算符號了,在堆內存上創建string對象,並將其返回給其引用s,又一個對象 

6.java的拆裝箱

    爲了滿足Java面向對象的思想,針對基本數據類型設計了相對於的包裝類。基本數據類型轉換成包裝類是裝箱,反之是拆箱。

    Java5.0之後引入了自動裝箱拆箱功能。

7.compareable 和 compartor的區別

 *  (01) "Comparable"
 *   它是一個排序接口,只包含一個函數compareTo()。
 *   一個類實現了Comparable接口,就意味着“該類本身支持排序”,它可以直接通過Arrays.sort() 或 Collections.sort()進行排序。
 *   (02) "Comparator"
 *   它是一個比較器接口,包括兩個函數:compare() 和 equals()。
 *   一個類實現了Comparator接口,那麼它就是一個“比較器”。其它的類,可以根據該比較器去排序。
 *
 *   綜上所述:Comparable是內部比較器,而Comparator是外部比較器。
 *   一個類本身實現了Comparable比較器,就意味着它本身支持排序;若它本身沒實現Comparable,也可以通過外部比較器Comparator進行排序。

2)數據結構和算法

常見的數據結構就是:數組,棧,隊列,集合,映射,鏈表,堆,二分搜索樹,紅黑樹,AVL平衡樹等一些數據結構。

我們要做的就是了解它們的實現原理和各自的優缺點。

數據結構部分面試遇到最多的就是:

1.ArrayList和LinkedList的區別,優缺點

List集合:
	ArrayList 基於動態數組,值可爲null 線程不安全 每次擴容0.5倍空間

	LinkedList 雙向鏈表 增刪速度快,查詢速度慢 線程不安全

	vector 線程安全,效率比ArrayList低 每次擴容2倍空間

	ArrayList是實現了基於動態數組的數據結構,而LinkedList是基於鏈表的數據結構

    Queue 隊列是一種特殊的線性表,它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作。


2.hashmap實現,擴容是怎麼做的,怎麼處理hash衝突,hashcode算法等
3.鏈表需要知道。LinkedHashMap一般再問LRU的時候會問到
4.二分搜索樹的特性和原理。前中後序遍歷寫出其中一種,當問到二分搜索樹的缺點的時候,你需要提出基於二分搜索樹的紅黑樹,說出他的特性。
5.堆的實現,最大堆,最小堆,優先隊列原理。

HashMap的本質 = 1個存儲Entry類對象的數組 + 多個單鏈表  https://blog.csdn.net/vking_wang/article/details/14166593

	HashMap   線程不安全 可以使用Collection類靜態方法Map map = Collections.synchronizedMap(new HashMap());
	                        獲取線程安全hashMap                                               
	          key可爲空(只能有一個null key)值可爲null                   
	          初始容量16,擴容<<1  2n
	          計算hash值方法不同(擾動函數)

	HashTable 線程安全
	          key value不能爲空(nullPointerException) key.hashCode();
	          初始容量11,擴容 2n+1

	LinkedHashMap HashMap子類,記錄了插入順序,具有HashMap全部特性,遍歷速度比HashMap慢

	TreeHashMap   保存的順序按照鍵排序,默認是升序排序,可以指定排序比較器。鍵值都不能爲空

	ConcurrentHashMap  數據結構  多個segment -> HashEntry

 

算法

算法其實就是我們平時常見的一些排序:選擇排序,插入排序,冒泡排序,希爾排序,歸併排序,快速排序。以及和數據結構相關聯的解決部分問題的一些計算方法。

算法面試遇到的一些題:

1.手寫快速排序,插入排序,冒泡排序
2.翻轉一個數字
3.翻轉一個鏈表
4.O(n)複雜度找出數組中和是9的兩個數的索引
5.寫出二分搜索樹前中後序遍歷中的其中一個
6.實現一個隊列,並能記錄隊列中最大的數。

二叉樹最大深度:
		//計算二叉樹的最大深度  BFS實現
    public static int maxDepth(TreeNode root){
        if(root == null){
            return 0;
        }

        List<TreeNode> list = new ArrayList<>();
        int count = 0;
        list.add(root);
        while (list.size()>0){
            int size = list.size();
            for(int i=size; i>0; i--){
                TreeNode node = list.remove(0);
                if(node.left != null){
                    list.add(node.left);
                }

                if(node.right != null){
                    list.add(node.right);
                }
            }
            count ++;
        }
        return count;
    }

    //二叉樹最大深度,遞歸實現
    public static int maxDepth1(TreeNode root){
        if(root == null){
            return 0;
        }
       if(root.left == null && root.right == null){
            return 1;
       }else {
            int left = maxDepth1(root.left);
            int right = maxDepth1(root.right);
            return 1+Math.max(left,right);
        }
    }
public static void quickSort(int[] arr, int L, int R) {
        int i = L;
        int j = R;

        int pivot = arr[(L + R) / 2];

        while (i <= j) {

            while (pivot > arr[i])
                i++;
            
            while (pivot < arr[j])
                j--;

            if (i <= j) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
                i++;
                j--;
            }
        }
        if (L < j)
            quickSort(arr, L, j);

        if (i < R)
            quickSort(arr, i, R);
    }

3)JVM虛擬機

JVM虛擬機我們需要知道他們內部組成:堆,虛擬機棧,本地方法棧,方法區,計數器。每一塊都存放什麼東西,以及垃圾回收的時候主要回收哪些塊的東西。GC-ROOT鏈是從哪些地方開始的,垃圾回收集算法(很少遇到問的)。

類加載ClassLoader已經雙親委派機制,類加載的過程,類加載的信息對應在JVM的哪些塊中。

(1)JVM的內存結構大概分爲:

	堆(heap):線程共享,所有的對象實例以及數組都要在堆上分配。回收器主要管理的對象。
	方法區(MEATHOD AREA):線程共享,存儲類信息、常量、靜態變量、即時編譯器編譯後的代碼。
	虛擬機棧(JVM Stack):線程私有、存儲局部變量表、操作棧、動態鏈接、方法出口,對象指針。
	本地方法棧(NATIVE METHOD STACK):線程私有。爲虛擬機使用到的Native 方法服務。如Java使用c或者c++編寫的接口服務時,代碼在此區運行。
	程序計數器(PC Register):線程私有。指向下一條要執行的指令

	(2)JVM垃圾回收算法
		標記-清除算法 (效率低,產生內存碎片)
		標記-整理算法 (效率低)
		複製算法		 (效率高,浪費內存空間)

		現代虛擬機採用 分代回收算法
			java堆分爲新生代和老年代。
			將內存分爲一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor 。當回收時,
			將Eden和Survivor中還存活着的對象一次性地複製到另外一塊Survivor空間上,
			最後清理掉Eden和剛纔用過的Survivor空間。當Survivor空間不夠用時,需要依賴其他內存(這裏指老年代)進行分配擔保
 

4)線程安全

當多個線程訪問一個對象的時候,如果不用考慮這些線程在運行時環境下的調度和交替執行,也不需要進行額外的同步,或者在調用方進行任何其他的協調操作,調用這個對象的行爲都可以獲取正確的結果,我們就認爲這個對象時線程安全的。

線程安全就是一些多線程下載,同步,鎖,死鎖,線程池。volatile關鍵字的特性,變量的原子性。以及java.util.concurrent包下的類,也需要了解一下。

一般會問的是手寫單例,以及雙重鎖式單例的優點。還有就是讓你自己實現一個多線程下載,看你怎麼設計。

java線程安全問題
   (1).*非線程安全存在於'實例變量'中,如果是方法內部的'局部變量'則不存在非線程安全
  (2)."鎖重入" 的概念是:自己可以再次獲取自己的內部鎖 (在一個synchronized方法內可以調用本地其他的synchronized方法); 當存在父子類繼承關係時,子類完全可以通過‘可重入鎖’調用父類的同步方法的。
   (3).線程共享變量和私有變量  靜態成員變量在同一個對象或者不同對象都是共享變量,非靜態成員變量在同一個對象間共享,在不同對象間不共享
    (4). synchronized關鍵字加到static方法上是給class類加鎖,而synchronized關鍵字加到非static方法上是給對象加鎖。 對象鎖只對同一個對象有用,而class鎖可以對類的所有對象實例起作用。

    	三大性質:單線程下操作可以認爲都是原子操作,多線程則不一定。
    (1) 原子性:java中原子操作包括除long和double之外的基本類型的賦值操作
    (2) 可見性:當多個線程訪問同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值,java提供volatile,synchronized和lock關鍵字來保證可見性。
    (3) 有序性:程序執行的順序按照代碼的先後順序執行。(爲了效率java允許編譯器和處理器對指令進行重排序,對單線程不會有影響,但是多線程下會有影響)java提供volatile,synchronized和lock關鍵字來保證有序性。
Thread線程相關:
		https://www.jianshu.com/p/fa6667dfb4ca
 (1) sleep 和 wait區別
	   由於CPU分配的每個線程的時間片極爲短暫(一般爲幾十毫秒),所以,CPU通過不停地切換線程執行,這樣就給程序員一種錯覺,以爲多個線程是在同時執行。sleep就是正在執行的線程主動讓出CPU,CPU去執行其他線程,在sleep指定的時間過後,CPU纔會回到這個線程上繼續往下執行,如果當前線程進入了同步鎖,sleep方法並不會釋放鎖,即使當前線程使用sleep方法讓出了CPU,但其他被同步鎖擋住了的線程也無法得到執行。

   (2) sleep方法只讓出了CPU,並不會釋放同步資源鎖
	     wait方法則讓當前線程退讓出同步資源鎖,以便其他等待該資源線程可以得到執行。只有調用了notify()方法,之前調用wait()的線程纔會解除wait狀態,可以去參與競爭同步資源鎖,進而得到執行。notify()會喚醒wait狀態的線程。
   
   (3)sleep可以在任何地方執行,wait只能在同步代碼塊中執行

   (4)join讓指定的線程先執行完再執行其他的線程,而且會阻塞當前線程。thread.join();

   (5) yield讓指定線程讓出當前cpu資源,從運行狀態轉爲就緒狀態,等待CPU調度。

   (6) volatile 保證可見性,禁止指令重排。

   	ReentrantReadWriteLock(讀寫鎖)。讀寫所允許同一時刻被多個讀線程訪問,但是在寫線程訪問時,所有的讀線程和其他的寫線程都會被阻塞
    ReentrantLock 可重入、可中斷、可限時、公平鎖
停止線程
		(1)非阻塞線程,設置標誌位,while循環時判斷是否可以繼續進行
		(2)阻塞線程(線程中sleep),interrupt(),方法打斷線程執行。   
				異常情況:線程休眠時,使用interrupt()方法來拋出InterruptedException異常,在catch中break出循環
		 在正常狀態下調用interrupt方法使用isInterrupted()作爲標誌位來退出,在阻塞狀態下通過捕獲異常來退出。因此使用interrupt()來退出線程的最好的方式應該是兩種情況都要考慮:
		(3)使用stop強行退出,會出現異常情況,不建議使用。(有可能數據不一致)
線程池
	優點   (1)重用線程池中的線程,避免頻繁創建和銷燬所帶來的性能損耗
		 (2)有效控制線程的最大併發數量,避免線程過大搶佔資源帶來的系統阻塞
		 (3)可以對線程進行一定的管理
    線程池運行規則:
    	(1)如果線程池中的線程數未達到核心線程數,則會立馬啓用一個核心線程去執行。
    	(2)如果線程池中的線程數已經達到核心線程數,且workQueue未滿,則將新線程放入workQueue中等待執行
    	(3)如果線程池中的線程數已經達到核心線程數但未超過非核心線程數,且workQueue已滿,則開啓一個非核心線程來執行任務。
    	(4)excute一個線程之後,如果線程池中的線程數已經超過非核心線程數,則拒絕執行該任務

    分類:(1) FixedThreadPool  (任務列隊長度Integer.MAX_VALUE)
    	  FixedThreadPool是一個核心線程數量固定的線程池,當所有的核心線程都在執行任務的時候,新的任務只能進入線程隊列中進行等待,直到有線程被空閒出來
    	 
    	 (2) SingleThreadExecutor  
    	 	SingleThreadExecutor的核心線程數只有1,任務列隊長度 Integer.MAX_VALUE
    	 
    	 (3) CacheThreadPool
    	 	沒有核心線程,每當我們添加一個新任務進來的時候,如果線程池中有空閒的線程,則由該空閒的線程執行新任務,如果沒有空閒線程,則創建新線程來執行任務
    	 	超時時間60秒  (適合執行大量耗時較少的操作,SynchronousQueue任務隊列其實相當於一個空集合,這將導致任何任務都會被立即執行)
    	
    	(4)ScheduleThreadPool
    		定時定期執行任務功能的線程池,核心線程固定(構造參數傳入),非核心線程無限制,非核心線程閒置會被馬上回收

    	如果調用了shutDown方法,則線程池處於shutDown狀態,此時不能接受新的任務,它會等待所有任務執行完畢。
    	如果調用shutDownNow方法,線程池處於stop狀態,此時不能接受新的任務,並且嘗試去終止正在執行的任務。
    	當線程池處於shutDown或者stop狀態,並且所有工作線程已經銷燬,任務列隊已被清空。此時線程池處於Terminaled狀態。
AsyncTask:內部封裝了線程池和handler的框架

    		onPreExecute() 主線程 初始化準備工作

    		doInBackgroud() 子線程,耗時操作

    		onProgressUpdate() 主線程,用於更新進度

    		onPostExecute() 主線程,任務執行完畢

 

5)編程思想

封裝,繼承,多態,抽象,反射,註解,設計模式,設計模式的原則。

面試中一般會問下:

1.抽象和接口有什麼不一樣
2.工作中常用的設計模式,一些源碼中的設計模式
3.具體給你一個設計模式讓你說說你對他的瞭解,比如觀察者,工廠。

淺談常用設計模式 
以上這些東西主要考察你的代碼設計能力。

6)網絡協議

1.互聯網的實現主要分爲幾層,http、ftp、tcp、ip分別位於哪一層。
2.http和https的區別
3.爲什麼tcp要經過三次握手,四次揮手
4.socket瞭解過嗎
一般http和https問的比較多,對稱加密和非對稱加密也會問。tcp和socket偶爾遇見問的。
 

三 Android相關

Android部分我就不分幾大塊了。直接列舉,但是列舉到的每一項都是面試經常會問到並且會延伸問的,所以需要深入的去研究。

1.四大組件有哪些,說出你對他們在Android系統中的作用和理解。

2.Activity生命週期,A啓動B兩個頁面生命週期怎麼運行的,爲什麼會 這樣,生命週期爲什麼這麼設計,你有了解過嗎。

3.四種啓動模式,內部堆棧是怎麼回事,你工作中怎麼使用的。

4.Activity的啓動過程,這個我強烈建議每個Android開發人員都要清楚的知道,並且跟一下源碼,幾個核心類的作用。你會對Android有一個更好的認識。

5.事件分發流程,怎麼處理滑動衝突。舉例:長按ListView的一個Item它變灰了。這個時候在滑動。item恢復原來的樣子,這個時候他們內部的事件傳遞是什麼樣子。有很多種問法,所以你一定要搞清楚。

6.自定義View,View的繪製流程。onMeasure,onLayout,onDraw都是什麼作用。

ViewGroup是怎麼分發繪製的。onDraw裏面怎麼去做繪製,Canvas,Path,Paint你都需要了解。

並且配合ValueAnimtor或者Scroller去實現動畫。有時候面試的會突發奇想問你ViewGroup是樹形結構,我想知道樹的深度,你怎麼計算,突然就變成了一個數據結構和算法的題。

自定義view生命週期
	->構造方法
	->onFinishInflate(從xml加載完成後調用)
	->onAttachedToWindow   (將view綁定到actvity所在的window,隨後開始進行所有view的繪製) 在宿主activity的onResume之後調用。
	->onMeasure
	->onLayout
	->onDraw
	->onWindowFocusChanged   (判斷view是否獲得焦點,可以判斷view進出前後臺)
	->onDetachedFromWindow   (activity銷燬後,view會從activity抽離,此時view銷燬)

7.Bitmap和Drawable

8.Animation和Animator

9.LinearLayout、RelativeLayout、FrameLayout三種常用佈局的特性,他在佈局的時候是怎麼計算的。效率如何。CoordinatorLayout配合AppbarLayout的使用,以及自定義Behavior。ConstraintLayout的使用。用來減少層級。

10.Handler消息機制,推薦看一下Looper的源碼

11.進程間通信,Binder機制

12.AsyncTask源碼看一下。

13.圖片的壓縮處理,三級緩存,Lru算法

14.分辨率和屏幕密度,以及計算一個圖片大小。mdpi,hdpi的關係和比例。

15.優化,內存優化,佈局優化,啓動優化,性能優化。內存泄露,內存溢出。怎麼優化,用了什麼工具,具體怎麼做的。

LeakCanary內存泄漏檢查工具

16.listView和RecycleView對比,以及緩存策略。

17.JNI(很少問)

18.MVC,MVP,MVVM

19.開源框架Okhttp,Glide,EventBus,Rxjava等,以及JetPack下的開源庫,要會用,還說說出一些東西,推薦 Retrofit,Okhttp,Glide,EventBus這些看一下源碼。

20.RecyclerView四大塊,能實現什麼效果,大致怎麼實現的,心裏要有數

21.DecorView,Window,WindowManager,PhoneWindow關係,以及個子的職責。
加分項:Kotlin,Gradle,Flutter,組件化,插件化,熱修復。

熱修復原理
    我們知道Java虛擬機 —— JVM 是加載類的class文件的,而Android虛擬機——Dalvik/ART VM 是加載類的dex文件,
    而他們加載類的時候都需要ClassLoader,ClassLoader有一個子類BaseDexClassLoader,而BaseDexClassLoader下有一個
    數組——DexPathList,是用來存放dex文件,當BaseDexClassLoader通過調用findClass方法時,實際上就是遍歷數組,
    找到相應的dex文件,找到,則直接將它return。而熱修復的解決方法就是將新的dex添加到該集合中,並且是在舊的dex的前面,
    所以就會優先被取出來並且return返回。
webView相關
	(1) webView生命週期:
			onResume     -> webView活躍狀態時回調,可以正常執行網頁的響應

			onPause      -> webView被切換到後臺使用,頁面失去焦點,變成不可見狀態。通知內核暫停所有動作,DOM解析,js執行...

			pauseTimers()   ->應用程序切換到後臺時調用,針對全應用。暫停所有webView的layout,javaScriptTimer,降低CPU功耗。

			resumeTimers()   -> 回覆pauseTimers時的動作

			destroy()        ->關閉activity時回調,webView destroy時仍綁定在activity上,需要先移除,再銷燬webView.

	(2) webViewClient幫助webView處理各種通知請求時間
			shouldOverrideUrlLoading作用: 打開網頁時不調用系統瀏覽器,而是在本webView中顯示,在網頁上所有加載都經過這個方法
			除了你主動用webview加載的url,其他的加載都會回調shouldOverrideLoading。後面還有一句註釋:post請求不會回調shouldOverrideLoading
			返回true和false的區別:返回ture 網頁會被加載到webView的歷史記錄中,加載後按返回鍵會回到這個網頁。返回false不會加載到webView歷史記錄中,返回也不會回到加載的網頁

		webChromeClient 輔助webView處理javaScript的對話框,網站標題,進度等。
			onProgressChanged() 獲取進度
			onReceivedTitle() 獲取web頁中的標題
UTF-8中文三個字節  英文一個字節

 

 

 

 

 

 

 

 

 

 

 

 

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