1. 程式人生 > >Android面試題整理(源自鴻洋大神公眾號【201803】的一篇BAT面試題推送)

Android面試題整理(源自鴻洋大神公眾號【201803】的一篇BAT面試題推送)

三月,想必各位程式設計師GG 此刻想要的,莫過於一篇面試寶典。鄙人不才,也從未系統的刷過面試題,以鴻洋大哥一篇面試題為引,略加整理,希望能幫到各位不知道看什麼小夥伴。(大部分知識都是有答案的).

原文連結: [https://mp.weixin.qq.com/s/p3l9wr4DX976Lr62-dYe8w(只有題)]

PS:其實在推送2天后就已經全部 總結出來了,只是新的CSDN 編輯器排版不會用,也沒時間來整理,終於有時間了,把格式排版下。(另外有些題我沒去搜索,是因為我覺得那些問的比較少,而且我對那些問題從未聽過,之後再進階的時候在回來看看,並在更新,現在的這些我覺得足夠複習了。)


主要分為以下幾部分:

(1)java面試題
(2)Android面試題
(3)高階技術面試題
(4)非技術性問題&HR問題彙總

1.java面試題

熟練掌握java是很關鍵的,大公司不僅僅要求你會使用幾個api,更多的是要你熟悉原始碼實現原理,甚至要你知道有哪些不足,怎麼改進,還有一些java有關的一些演算法,設計模式等等。

(一) java基礎面試知識點

  1. java中==和equals和hashCode的區別
    基本資料型別(int,char,long,boolean等)使用 = =,引用字元型別使用 equals,hashmap中,key.hashCode 出值先進行值對比,在進行equals 對比,然後在確定是否加入HashMap
  2. int、char、long各佔多少位元組數
    Int -4,char -2,float: 4個位元組 double: 8個位元組 long: 8個位元組,short-2
  3. int與integer的區別
    1、Integer是int的包裝類,int則是java的一種基本資料型別
    2、Integer變數必須例項化後才能使用,而int變數不需要
    3、Integer實際是物件的引用,當new一個Integer時,實際上是生成一個指標指向此物件;而int則是直接儲存資料值
    4、Integer的預設值是null,int的預設值是0
  4. 探探對java多型的理解
    面向物件的三大基本特徵:封裝、繼承、多型
    1.(封裝)這個封裝其實就是面嚮物件語言的精髓,在這裡一些都是物件,我們通過封裝,只為使用者提供介面,而隱藏了內部的具體實現,比如插班。不用考慮內部,我們只需要插統一的一個插口,就是呼叫這個介面。
    2.(繼承)
    ①提高了程式碼的複用性。
    ②類與類之間產生了關係,關係的出現
    ③對父類功能進行重定義.
    3.(多型)同一訊息可以根據傳送物件的不同而採用多種不同的行為方式,父類引用指向子類物件,在執行期間判斷所引用物件的實際型別,根據其實際的型別呼叫其相應的方法。用我的話就是智慧判斷你需要呼叫的方法!
  5. String、StringBuffer、StringBuilder區別
    String 字串常量
    StringBuffer 字串變數(執行緒安全)
    StringBuilder 字串變數(非執行緒安全)
    1.String 型別和 StringBuffer 型別的主要效能區別其實在於 String 是不可變的物件, 因此在每次對 String 型別進行改變的時候其實都等同於生成了一個新的 String 物件,然後將指標指向新的 String 物件,所以經常改變內容的字串最好不要用 String,因為每次生成物件都會對系統性能產生影響.而如果是使用 StringBuffer 類則結果就不一樣了,每次結果都會對 StringBuffer 物件本身進行操作,而不是生成新的物件,再改變物件引用
    2.有時候你會很驚訝的發現,生成 String S1 物件的速度簡直太快了,而這個時候 StringBuffer 居然速度上根本一點都不佔優勢。其實這是 JVM 的一個把戲,在 JVM 眼裡,這個
    String S1 = “This is only a” + “ simple” + “test”; 其實就是:
    String S1 = “This is only a simple test”; 所以當然不需要太多的時間了
    3.在大部分情況下 StringBuilder > StringBuffer ,不保證同步,
  6. 什麼是內部類?內部類的作用

  7. 1.內部類可以直接訪問外部類中的成員(包括私有成員),
    而外部類要訪問內部類中的成員必須要建立內部類的物件
    2.內部類可分為靜態內部類,動態內部類,匿名類
    靜態內部類:性質上和外部類沒什麼區別,只是形式上是寫在另外一個類裡面,通過另外一個類名訪問。所以一個類應不應該被寫為靜態內部類純看個人喜好。對我來說,一個類滿足以下條件時我就把它寫為靜態內部類:
    ① 類的程式碼量不多,可能只是定義一個結構體,一個介面,或者一丁點邏輯程式碼
    ② 類只起到輔助作用,一般不單獨拿出來用
    ③. 和它所在的類關係非常緊密,以至於它的修改一般都是由它所在類引起動態內部類:
    動態內部類例項化之後會保留它所在類的例項,所以內部類可以訪問它所在類的動態屬性。動態內部類可以模擬多繼承。
    匿名內部類其實也是一種動態內部類,只是沒有類名。
  8. 抽象類和介面區別
    抽象類和介面對比
    抽象類的意義
    利於程式碼的維護和重用,我目前使用最頻繁的就是BaseActivity 基類。(初始化呼叫狀態列的方法)以及網路請求中的錯誤型別判斷。
  9. 抽象類與介面的應用場景
    ①interface的應用場合
    A. 類與類之前需要特定的介面進行協調,而不在乎其如何實現。(比如jni中的呼叫)
    B. 作為能夠實現特定功能的標識存在,也可以是什麼介面方法都沒有的純粹標識。
    C. 需要將一組類視為單一的類,而呼叫者只通過介面來與這組類發生聯絡。
    D. 需要實現特定的多項功能,而這些功能之間可能完全沒有任何聯絡。
    ②abstract class的應用場合
    一句話,在既需要統一的介面,又需要例項變數或預設的方法的情況下,就可以使用它。最常見的有:
    A. 定義了一組介面,但又不想強迫每個實現類都必須實現所有的介面。可以用abstract class定義一組方法體,甚至可以是空方法體,然後由子類選擇自己所感興趣的方法來覆蓋。
    B. 某些場合下,只靠純粹的介面不能滿足類與類之間的協調,還必需類中表示狀態的變數來區別不同的關係。abstract的中介作用可以很好地滿足這一點。
    C. 規範了一組相互協調的方法,其中一些方法是共同的,與狀態無關的,可以共享的,無需子類分別實現;而另一些方法卻需要各個子類根據自己特定的狀態來實現特定的功能
  10. 抽象類是否可以沒有方法和屬性?
    ?????? (作者偷懶沒去總結)
  11. 介面的意義
    功能的抽象,通過介面可以實現不相關類的相同行為,而不需要了解物件所對應的類。
    通過介面可以指明多個類需要實現的方法。
  12. 父類的靜態方法能否被子類重寫
    來說一下我的觀點,父類的靜態方法不能被子類繼承,更談不上重寫,就算是子類中有一個和父類一模一樣的靜態方法,那也是子類本身的,和父類的那個靜態方法不是一回事。方法加靜態後就屬於類不屬於物件了。
  13. 程序和執行緒的區別
    1)程序是資源的分配和排程的一個獨立單元,而執行緒是CPU排程的基本單元
    2)同一個程序中可以包括多個執行緒,並且執行緒共享整個程序的資源(暫存器、堆疊、上下文),一個進行至少包括一個執行緒。
    3)執行緒是輕量級的程序,它的建立和銷燬所需要的時間比程序小很多,所有作業系統中的執行功能都是建立執行緒去完成的
    5)執行緒中執行時一般都要進行同步和互斥,因為他們共享同一程序的所有資源
    6)執行緒有自己的私有屬性TCB,執行緒id,暫存器、硬體上下文,而程序也有自己的私有屬性程序控制塊PCB,這些私有屬性是不被共享的,用來標示一個程序或一個執行緒的標誌
  14. final,finally,finalize的區別
    1)Final用於修飾類、成員變數和成員方法。final修飾的類,不能被繼承(String、StringBuilder、StringBuffer、Math,不可變類),其中所有的方法都不能被重寫,所以不能同時用abstract和final修飾類
    2)Finally通常和try catch搭配使用,保證不管有沒有發生異常,資源都能夠被釋放(釋放連線、關閉IO流)。
    3)Finalize是object類中的一個方法,子類可以重寫finalize()方法實現對資源的回收。垃圾*回收只負責回收記憶體,並不負責資源的回收,資源回收要由程式設計師完成,Java虛擬機器在垃圾回收之前會先呼叫垃圾物件的finalize方法用於使物件釋放資源(如關閉連線、關閉檔案),之後才進行垃圾回收。
  15. 序列化的方式
    1)有的時候我們想要把一個Java物件變成位元組流的形式傳出去,有的時候我們想要從一個位元組流中恢復一個Java物件。
    2)我常用Serializable介面 實現序列化,在傳遞Bean 資料包時候
  16. Serializable 和Parcelable 的區別
    1)Serializable的作用是為了儲存物件的屬性到本地檔案、資料庫、網路流、rmi以方便資料傳輸,當然這種傳輸可以是程式內的也可以是兩個程式間的。而Android的Parcelable的設計初衷是因為Serializable效率過慢
    2)Parcelable的效能比Serializable好,在記憶體開銷方面較小,所以在記憶體間資料傳輸時推薦使用Parcelable,如activity間傳輸資料,而Serializable可將資料持久化方便儲存,所以在需要儲存或網路傳輸資料時選擇Serializable
  17. 靜態屬性和靜態方法是否可以被繼承?是否可以被重寫?以及原因?
    一旦靜態,就不屬於物件了,因此不存在重新和繼承
  18. 靜態內部類的設計意圖
    ?????? (作者偷懶沒去總結)
  19. 成員內部類
    成員內部類也是最普通的內部類,它是外圍類的一個成員,所以它可以無限制的訪問外圍類的所有成員屬性和方法,儘管是private的,但是外圍類要訪問內部類的成員屬性和方法則需要通過內部類例項來訪問。
    在成員內部類中要注意兩點:
    1)成員內部類中不能存在任何static的變數和方法;
    2)成員內部類是依附於外圍類的,所以只有先建立了外圍類才能夠建立內部類。
  20. 靜態內部類
    **靜態內部類與非靜態內部類之間存在一個最大的區別:非靜態內部類在編譯完成之後會隱含地儲存著一個引用,該引用是指向建立它的外圍內,但是靜態內部類卻沒有。
    沒有這個引用就意味著:
    它的建立是不需要依賴於外圍類的。
    它不能使用任何外圍類的非static成員變數和方法。**
  21. 成員內部類、靜態內部類、區域性內部類和匿名內部類的理解,以及專案中的應用
    ?????? (作者偷懶沒去總結)
  22. 談談對kotlin的理解
    2017年穀歌I/O大會的最後,谷歌宣佈將Kotlin語言作為安卓開發的一級程式語言
    Kotlin程式可以使用所有現有的Java框架和庫,也就是說所有的現有程式不需要更改就可以直接被呼叫。
    Kotlin可以輕鬆學習,平易近人。它的規則及其簡單,語法規則少,易於學習。
    Kotlin是開放原始碼,沒有收費。雖然java也是開源語言,但是相比於其他的非開源的還是有一定優勢的。
    Kotlin的空安全性很好,使用Kotlin,你可以用更少的程式碼獲得更多的功能。 而你寫的程式碼越少,你犯的錯誤就越少。
  23. 閉包和區域性內部類的區別
    1)因為Java不支援多繼承,支援實現多個介面。但有時候會存在一些使用介面很難解決的問題,這個時候我們可以利用內部類提供的、可以繼承多個具體的或者抽象的類的能力來解決這些程式設計問題。可以這樣說,介面只是解決了部分問題,而內部類使得多重繼承的解決方案變得更加完整。
    2)區域性內部類是巢狀在方法和作用域內的,對於這個類的使用主要是應用與解決比較複雜的問題,想建立一個類來輔助我們的解決方案,到那時又不希望這個類是公共可用的,所以就產生了區域性內部類,區域性內部類和成員內部類一樣被編譯,只是它的作用域發生了改變,它只能在該方法和屬性中被使用,出了該方法和屬性就會失效。
  24. string 轉換成 integer的方式及原理
    1)靜態方法Integer.toString(intvalues),
    2)成員方法 a.toString();
    3.)String.valueof(a)
    4)String轉integer 需要先進行非空判斷,Integer.valueOf(str);

(二) java深入原始碼級的面試題(有難度)

  1. 哪些情況下的物件會被垃圾回收機制處理掉?
    1) 沒有被引用的
    2)當記憶體佔用過多,弱引用
    3)垃圾回收他是在虛擬機器空閒的時候或者記憶體緊張的時候執行的,什麼時候回收不是由程式設計師來控制的,需要被回收的時候並不會馬上被回收,而是將其放入到一個準備回收的佇列,去執行finalize方法。這也就是java比較耗記憶體的原因之一。
  2. 講一下常見編碼方式?
    在studio的右下角 有一個編碼選擇,通常有GBK,utf-8,utf-16,ASCII碼
    utf-8編碼中的中文佔幾個位元組;int型幾個位元組?
    UTF-8不是固定字長編碼的,而是一種變長的編碼方式。它可以使用1~4個位元組表示一個符號,根據不同的符號而變化位元組長度。
    我在Notepad++ 測試 長度 為 3位元組,
  3. 靜態代理和動態代理的區別,什麼場景使用
    1)為某個物件提供一個代理,以控制對這個物件的訪問。代理類負責請求的預處理、過濾、將請求分派給委託類處理、以及委託類執行完請求後的後續處理。
    2)所謂靜態也就是在程式執行前就已經存在代理類的位元組碼檔案,代理類和委託類的關係在執行前就確定了。
  4. Java的異常體系
    1) Thorwable類所有異常和錯誤的超類,有兩個子類Error和Exception,分別表示錯誤和異常。
    其中異常類Exception又分為執行時異常(RuntimeException)和非執行時異常,
    2) Error是程式無法處理的錯誤,比如OutOfMemoryError、 Exception是程式本身可以處理的異常,這種異常分兩大類執行時異常和非執行時異常。
    3) 執行時異常都是RuntimeException類及其子類異常,如NullPointerException、IndexOutOfBoundsException等, 這些異常是不檢查異常,非執行時異常是RuntimeException以外的異常,型別上都屬於Exception類及其子類。IOException,JSONException 從程式語法角度講是必須進行處理的異常,如果不處理,程式就不能編譯通過。
  5. 談談你對解析與分派的認識。
    ?????? (作者偷懶沒去總結)
  6. 修改物件A的equals方法的簽名,那麼使用HashMap存放這個物件例項的時候,會呼叫哪個equals方法
    ??????? (作者偷懶沒去總結)
  7. Java中實現多型的機制是什麼?
    多型自我理解就是多種狀態!
    多型就是指程式中定義的引用變數所指向的具體型別和通過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式執行期間才確定,該引用變數發出的方法呼叫到底是哪個類中實現的方法,必須在由程式執行期間才能決定。因為在程式執行時才確定具體的類,這樣,即不修改程式程式碼就可以改變程式執行時所繫結的具體程式碼,讓程式可以選擇多個執行狀態,這就是多型性。
  8. 如何將一個Java物件序列化到檔案裡?
    ?????? (作者偷懶沒去總結)
  9. 說說你對Java反射的理解
    1)最簡單的一句話來說就是:反射就是把Java類中的各種成分對映成相應的Java類。類中有什麼資訊,它就可以獲得什麼資訊,不過前提是得知道類的名字,要不就沒有後文了
    2)JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
  10. 說說你對Java註解的理解
    首先先說下我接觸過的2種註解,一種是xUtils框架另外一種是ButterKnife(黃油刀),黃油刀註解真的很方便,對於需要一次性初始化大量的view 尤為方便。另外也可以對監聽方法進行註解,xUtils只是瞭解,ButterKnife也只是使用了一段時間,後來在工作中,老大告訴我但凡是註解都是基於反射機制,影響效能,還是最原始的方法最好。現在常用的註解就是 @Deprecated 用來處理廢棄程式碼,其他沒深入瞭解.
  11. 說說你對依賴注入的理解
    本文從開頭到現在提到的一系列依賴,只要不是由內部生產(比如初始化、建構函式 __construct 中通過工廠方法、自行手動 new 的),而是由外部以引數或其他形式注入的,都屬於依賴注入(DI) 。
  12. 說一下泛型原理,並舉例說明
    泛型的本質是引數化型別,也就是說所操作的資料型別被指定為一個引數。這種引數型別可以用在類、介面和方法的建立中,分別稱為泛型類、泛型介面、泛型方法。提高程式碼的複用
  13. Java中String的瞭解
    1)String類是final類,也即意味著String類不能被繼承,並且它的成員方法都預設為final方法。
    2)從原始碼中可以看出String類其實是通過char陣列來儲存字串的。
    3)“String物件一旦被建立就是固定不變的了,對String物件的任何改變都不影響到原物件,相關的任何change操作都會生成新的物件”。
  14. String為什麼要設計成不可變的?
    1) 假若字串物件允許改變,那麼將會導致各種邏輯錯誤,比如改變一個物件會影響到另一個獨立物件.
    2) String被許多的Java類(庫)用來當做引數,例如 網路連線地址URL,檔案路徑path,還有反射機制所需要的String引數等, 假若String不是固定不變的,將會引起各種安全隱患。
  15. Object類的equal和hashCode方法重寫,為什麼?
    1)hashCode的意思就是雜湊碼,也就是雜湊碼,雜湊碼是沒有規律的,如果x與y是兩個不同的物件,那麼x.hashCode()與y.hashCode()基本是不會相同的
    2)因為Object物件只與自身相等,所以同一個物件的地址總是相等的,計算取得的雜湊碼也必然相等,對於不同的物件,由於地址不同,所獲取的雜湊碼自然也不會相等。因此到這裡我們就明白了,兩個物件通過呼叫equals方法是相等的,那麼這兩個物件呼叫hashCode方法必須返回相同的整數。

(三) 資料結構

  1. 常用資料結構簡介
    1)資料的邏輯結構
    集合,線性結構,樹形結構,圖形結構
    2)資料的物理結構 :指資料的邏輯結構在計算機儲存空間的存放形式。
    有順序、連結、索引、雜湊等多種,常用的有順序儲存結構和鏈式儲存結構。順序映像藉助元素在儲存器中的相對位置來表示資料元素之間的邏輯關係。非順序映像藉助指示元素儲存位置的指標(pointer)來表示資料元素之間的邏輯關係
  2. 併發集合瞭解哪些?
    在新增的Concurrent包中,BlockingQueue(阻塞佇列)很好的解決了多執行緒中,如何高效安全“傳輸”資料的問題。通過這些高效並且執行緒安全的佇列類,為我們快速搭建高質量的多執行緒程式帶來極大的便利。
    1) 阻塞列表,使用LinkedBlockingDeque類。
    2) 用在生產者與消費者資料的阻塞列表,使用LinkedTransferQueue類。
    3) 使用優先順序排序元素的阻塞列表,使用PriorityBlockingQueue類。
    4) 儲存延遲元素的阻塞列表,使用DelayQueue類
  3. 列舉java的集合以及集合之間的繼承關係
    ?????? (作者偷懶沒去總結)
  4. 集合類以及集合框架
    學習Java集合框架下大致可以分為如下五個部分:List列表、Set集合、Map對映、迭代器(Iterator、Enumeration)、工具類(Arrays、Collections)。
    容器類介紹以及之間的區別
    (容器類估計很多人沒聽這個詞,Java容器主要可以劃分為4個部分:List列表、Set集合、Map對映、工具類(Iterator迭代器、Enumeration列舉類、Arrays和Collections),具體的可以看看這篇博文 Java容器類 http://alexyyek.github.io/2015/04/06/Collection/
    List,Set,Map的區別
    List
    1.可以允許重複的物件。
    2.可以插入多個null元素。
    3.是一個有序容器,保持了每個元素的插入順序,輸出的順序就是插入的順序。
    4.常用的實現類有 ArrayList、LinkedList 和 Vector。ArrayList 最為流行,它提供了使用索引的隨意訪問,而 LinkedList 則對於經常需要從 List 中新增或刪除元素的場合更為合適。
    Set:
    1.不允許重複物件
    2.無序容器,你無法保證每個元素的儲存順序,TreeSet通過 Comparator 或者 Comparable 維護了一個排序順序。
    3.只允許一個 null 元素
    4.Set 介面最流行的幾個實現類是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基於 HashMap 實現的 HashSet;
    Map
    1.Map不是collection的子介面或者實現類。Map是一個介面。
    2.Map 的 每個 Entry 都持有兩個物件,也就是一個鍵一個值,Map 可能會持有相同的值物件但鍵物件必須是唯一的。
    3.TreeMap 也通過 Comparator 或者 Comparable 維護了一個排序順序。
    4.Map 裡你可以擁有隨意個 null 值但最多隻能有一個 null 鍵。
    5.Map 介面最流行的幾個實現類是 HashMap、LinkedHashMap、 TreeMap。
    (HashMap、TreeMap最常用)
  5. List和Map的實現方式以及儲存方式
    1)List(有序,可重複)
    A:Map集合的資料結構僅僅針對鍵有效,與值無關。
    B:儲存的是鍵值對形式的元素,鍵唯一,值可重複。
    2)HashMap也用到了雜湊碼的演算法,以便快速查詢一個鍵,
  6. HashMap的實現原理
    HashMap實際上是一個“連結串列雜湊”的資料結構,即陣列和連結串列的結合體。
    儲存:當我們往HashMap中put元素的時候,先根據key的hashCode重新計算hash值,根據hash值得到這個元素在陣列中的位置(即下標), 如果陣列該位置上已經存放有其他元素了,那麼在這個位置上的元素將以連結串列的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。如果陣列該位置上沒有元素,就直接將該元素放到此陣列中的該位置上。
    讀取:從HashMap中get元素時,首先計算key的hashCode,找到陣列中對應位置的某一元素,然後通過key的equals方法在對應位置的連結串列中找到需要的元素。
  7. HashMap資料結構?
    ?????? (作者偷懶沒去總結)
  8. HashMap原始碼理解
    ?????? (作者偷懶沒去總結)
  9. HashMap如何put資料(從HashMap原始碼角度講解)?
    儲存:當我們往HashMap中put元素的時候,先根據key的hashCode重新計算hash值,根據hash值得到這個元素在陣列中的位置(即下標), 如果陣列該位置上已經存放有其他元素了,那麼在這個位置上的元素將以連結串列的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。如果陣列該位置上沒有元素,就直接將該元素放到此陣列中的該位置上。
  10. ConcurrentHashMap的實現原理
    ?????? (作者偷懶沒去總結)
  11. ArrayMap和HashMap的對比
    HashMap內部是使用一個預設容量為16的陣列來儲存資料的,而陣列中每一個元素卻又是一個連結串列的頭結點,所以,更準確的來說,HashMap內部儲存結構是使用雜湊表的拉鍊結構(陣列+連結串列),這種儲存資料的方法叫做拉鍊法
    假設資料量都在千級以內的情況下:
    1、資料量不大,最好在千級以內,資料結構型別為Map型別
    2、如果key型別為其它的型別,則使用ArrayMap
  12. HashTable實現原理
    以淘汰
  13. TreeMap具體實現
    TreeMap是Java內部實現比較複雜的集合類之一。與HashMap不一樣,TreeMap的底層不是用雜湊表實現的,而是用紅黑樹實現的。當需要查詢的元素是排好序的,TreeMap的優勢就體現出來了。<1>每個節點的顏色是紅色或黑色。<2>根節點必須是黑色的。<3>每個葉節點是黑色的(葉節點是指樹尾端的NULL節點)。<4>如果一個節點是紅色的,那麼它的子節點必須是黑色。即,不能有連續的紅色節點。<5>對於任意一個節點,從它到葉節點的每條路徑包含相同數量的黑色節點。
  14. HashMap和HashTable的區別
    以淘汰
  15. HashMap與HashSet的區別
    1)HashSet實現了Set介面,它不允許集合中有重複的值,當我們提到HashSet時,第一件事情就是在將物件儲存在HashSet之前,要先確保物件重寫equals()和hashCode()方法,這樣才能比較物件的值是否相等,以確保set中沒有儲存相等的物件。如果我們沒有重寫這兩個方法,將會使用這個方法的預設實現。
    2)HashMap實現了Map介面,Map介面對鍵值對進行對映。Map中不允許重複的鍵。Map介面有兩個基本的實現,HashMap和TreeMap。TreeMap儲存了物件的排列次序,而HashMap則不能。HashMap允許鍵和值為null。HashMap是非synchronized的,但collection框架提供方法能保證HashMap synchronized,這樣多個執行緒同時訪問HashMap時,能保證只有一個執行緒更改Map。
  16. HashSet與HashMap怎麼判斷集合元素重複?
    其實HashSet 只是實現了HashMap 的 key部分,都是無序的儲存形勢
    1)HashSet不能新增重複的元素,當呼叫add(Object)方法時候,
    首先會呼叫Object的hashCode方法判hashCode是否已經存在,如不存在則直接插入元素;
    如果已存在則呼叫Object物件的equals方法判斷是否返回true,如果為true則說明元素已經存在,如為false則插入元素。
    2)HashMap中判斷元素是否相同主要有兩個方法,一個是判斷key是否相同,一個是判斷value是否相同。那就是首先得hashCode相同,然後根據key得到的 value 進行 equals 如果相同,新加入的放在鏈頭,最先加入的放在鏈尾。如果陣列該位置上沒有元素,就直接將該元素放到此陣列中的該位置上
  17. 集合Set實現Hash怎麼防止碰撞
    ?????? (作者偷懶沒去總結)
  18. ArrayList和LinkedList的區別,以及應用場景
    ArrayList是基於陣列實現的,LinkedList是基於雙鏈表實現的:(雙向連結串列也叫雙鏈表,是連結串列的一種,它的每個資料結點中都有兩個指標,分別指向直接後繼和直接前驅。所以,從雙向連結串列中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。)
    (1)如果應用程式對各個索引位置的元素進行大量的存取或刪除操作,ArrayList物件要遠優於LinkedList物件;
    ( 2 ) 如果應用程式主要是對列表進行迴圈,並且迴圈時候進行插入或者刪除操作,LinkedList物件要遠優於ArrayList物件;
  19. 陣列和連結串列的區別
  20. 二叉樹的深度優先遍歷和廣度優先遍歷的具體實現
  21. 堆的結構
  22. 堆和樹的區別
  23. 堆和棧在記憶體中的區別是什麼(解答提示:可以從資料結構方面以及實際實現方面兩個方面去回答)?
  24. 什麼是深拷貝和淺拷貝
  25. 手寫連結串列逆序程式碼
  26. 講一下對樹,B+樹的理解
  27. 講一下對圖的理解
  28. 判斷單鏈表成環與否?
  29. 連結串列翻轉(即:翻轉一個單項鍊表)
  30. 合併多個單有序連結串列(假設都是遞增的)
    ?????? (尼瑪,這些都太深奧了,查了也不懂。。GG)

(四) 執行緒、多執行緒和執行緒池

  1. 開啟執行緒的三種方式?
    1)首先第一種啟用方法是通過繼承Thread類,並改寫run方法來實現一個執行緒
    2)第二種啟用方式實現Runnable物件,並new Thread,常用第一種
    3)第三種啟用方式通過Handler啟動執行緒,handler.post(run)
    4)Thread和Runnable是實現java多執行緒的2種方式,runable是介面,thread是類,最終都需要通過thread.start()來使執行緒處於可執行狀態。
  2. 執行緒和程序的區別?
    1)程序是資源的分配和排程的一個獨立單元,而執行緒是CPU排程的基本單元
    用我的話說就類似人類,每個人都是一個程序,負責排程,比如我現在開個執行緒去吃零食,在開個執行緒去看視訊。程序用來分配資源,共享一個大腦和心臟.
    2)同一個程序中可以包括多個執行緒,並且執行緒共享整個程序的資源(暫存器、堆疊、上下文),一個進行至少包括一個執行緒(你活著不就是一直開著呼吸這個執行緒麼)。
    3)程序結束後它擁有的所有執行緒都將銷燬,而執行緒的結束不會影響同個程序中的其他執行緒的結束.
    4)執行緒是輕量級的程序,它的建立和銷燬所需要的時間比程序小很多,所有作業系統中的執行功能都是建立執行緒去完成的
    5)執行緒中執行時一般都要進行同步和互斥,因為他們共享同一程序的所有資源
    6)執行緒有自己的私有屬性TCB,執行緒id,暫存器、硬體上下文,而程序也有自己的私有屬性程序控制塊PCB,這些私有屬性是不被共享的,用來標示一個程序或一個執行緒的標誌
  3. 為什麼要有執行緒,而不是僅僅用程序?
    1)程序只能在一個時間幹一件事,如果想同時幹兩件事或多件事,程序就無能為力了。
    程序在執行的過程中如果阻塞,例如等待輸入,整個程序就會掛起,即使程序中有些工作不依賴於輸入的資料,也將無法執行。
    2)如果把我們上課的過程看成一個程序的話,那麼我們要做的是耳朵聽老師講課,手上還要記筆記,腦子還要思考問題,這樣才能高效的完成聽課的任務。而如果只提供程序這個機制的話,上面這三件事將不能同時執行,同一時間只能做一件事,聽的時候就不能記筆記,也不能用腦子思考,
    這是其一;如果老師在黑板上寫演算過程,我們開始記筆記,而老師突然有一步推不下去了,阻塞住了,他在那邊思考著,而我們呢,也不能幹其他事,即使你想趁此時思考一下剛才沒聽懂的一個問題都不行,這是其二
  4. 執行緒優點
    除了提高程序的併發度,執行緒還有個好處,就是可以有效地利用多處理器和多核計算機。現在的處理器有個趨勢就是朝著多核方向發展,在沒有執行緒之前,多核並不能讓一個程序的執行速度提高,原因還是上面所有的兩點限制。但如果講一個程序分解為若干個執行緒,則可以讓不同的執行緒執行在不同的核上,從而提高了程序的執行速度
  5. run()和start()方法區別
    1)用start方法來啟動執行緒,真正實現了多執行緒執行,這時無需等待run方法體(跳過)程式碼執行完畢而直接繼續執行下面的程式碼。通過呼叫Thread類的 start()方法來啟動一個執行緒,這時此執行緒處於就緒(可執行)狀態,並沒有執行,一旦得到cpu時間片,就開始執行run()方法,這裡方法 run()稱為執行緒體,它包含了要執行的這個執行緒的內容,Run方法執行結束,此執行緒隨即終止。
    2)run()方法只是類的一個普通方法而已,如果直接呼叫Run方法,程式中依然只有主執行緒這一個執行緒,其程式執行路徑還是隻有一條,還是要順序執行,還是要等待run方法體執行完畢後才可繼續執行下面的程式碼,這樣就沒有達到寫執行緒的目的。
  6. 如何控制某個方法允許併發訪問執行緒的個數?
    synchronized關鍵字主要解決多執行緒共享資料同步問題。
    synchronized是利用鎖的機制,使變數或程式碼塊在某一時該只能被一個執行緒訪問。
    用於在多個執行緒間通訊 時能夠獲得資料共享。Synchronized用於實現同步機制,
    synchronized取得的鎖都是物件;每個物件只有一個鎖(lock)與之相關聯;實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以儘量避免無謂的同步控制,縮小同步塊內容。
  7. 在Java中wait和seelp方法的不同;
    1)這兩個方法來自不同的類分別是Object ,Thread
    2)最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他執行緒可以使用同步控制塊或者方法(鎖程式碼塊和方法鎖)。
    3)wait,notify和notifyAll只能在同步控制方法或者同步控制塊裡面使用,而sleep可以在任何地方使用(使用範圍)
    4)sleep必須捕獲異常,而wait,notify和notifyAll不需要捕獲異常
    5)注意sleep()方法是一個靜態方法,也就是說他只對當前物件有效,通過t.sleep()讓t物件進入sleep,這樣的做法是錯誤的,它只會是使當前執行緒被sleep 而不是t執行緒
    6)wait屬於Object的成員方法,一旦一個物件呼叫了wait方法,必須要採用notify()和notifyAll()方法喚醒該程序;如果執行緒擁有某個或某些物件的同步鎖,那麼在呼叫了wait()後,這個執行緒就會釋放它持有的所有同步資源。
  8. 談談wait/notify關鍵字的理解
    wait( ),notify( ),notifyAll( )都不屬於Thread類,而是屬於Object基礎類,也就是每個物件都有wait( ),notify( ),notifyAll( ) 的功能,因為每個物件都有鎖,鎖是每個物件的基礎,當然操作鎖的方法也是最基礎了。
    當需要呼叫以上的方法的時候,一定要對競爭資源進行加鎖,如果不加鎖的話,則會報 IllegalMonitorStateException 異常
    當想要呼叫wait( )進行執行緒等待時,必須要取得這個鎖物件的控制權(物件監視器),一般是放到synchronized(obj)程式碼中。
    notify( )方法只會通知等待佇列中的第一個相關執行緒(不會通知優先順序比較高的執行緒)
    notifyAll( )通知所有等待該競爭資源的執行緒(也不會按照執行緒的優先順序來執行)
    假設有三個執行緒執行了obj.wait( ),那麼obj.notifyAll( )則能全部喚醒tread1,thread2,thread3,但是要繼續執行obj.wait()的下一條語句,必須獲得obj鎖,因此,tread1,thread2,thread3只有一個有機會獲得鎖繼續執行,例如tread1,其餘的需要等待thread1釋放obj鎖之後才能繼續執行。
    當呼叫obj.notify/notifyAll後,呼叫執行緒依舊持有obj鎖,因此,thread1,thread2,thread3雖被喚醒,但是仍無法獲得obj鎖。直到呼叫執行緒退出synchronized塊,釋放obj鎖後,thread1,thread2,thread3中的一個才有機會獲得鎖繼續執行。
  9. 什麼導致執行緒阻塞?
    1)執行緒執行了Thread.sleep(intmillsecond);方法,當前執行緒放棄CPU,睡眠一段時間,然後再恢復執行
    2)執行緒執行一段同步程式碼,但是尚且無法獲得相關的同步鎖,只能進入阻塞狀態,等到獲取了同步鎖,才能回覆執行。
    3)執行緒執行了一個物件的wait()方法,直接進入阻塞狀態,等待其他執行緒執行notify()或者notifyAll()方法。
    4)執行緒執行某些IO操作,因為等待相關的資源而進入了阻塞狀態。比如說監聽system.in,但是尚且沒有收到鍵盤的輸入,則進入阻塞狀態。
  10. 執行緒如何關閉?
    1)使用退出標誌,使執行緒正常退出,也就是當run方法完成後執行緒終止。
    2)使用stop方法強行終止執行緒(這個方法不推薦使用)。
    3)使用interrupt(因特R 普特)方法中斷執行緒。
  11. 講一下java中的同步的方法
    1)同步方法.synchronized.
    2)同步程式碼塊.synchronized.
    3)特殊域變數,volatile,注意不能修飾final的變數.
    a.volatile關鍵字為域變數的訪問提供了一種免鎖機制
    b.使用volatile修飾域相當於告訴虛擬機器該域可能會被其他執行緒更新
    c.因此每次使用該域就要重新計算,而不是使用暫存器中的值
    d.volatile不會提供任何原子操作,它也不能用來修飾final型別的變數
  12. 資料一致性如何保證?
  13. 如何保證執行緒安全?
  14. 如何實現執行緒同步?
    synchronized關鍵字和鎖
    a)Lock使用起來比較靈活,但需要手動釋放和開啟;採用synchronized不需要使用者去手動釋放鎖,當synchronized方法或者synchronized程式碼塊執行完之後,系統會自動讓執行緒釋放對鎖的佔用;
    b)Lock不是Java語言內建的,synchronized是Java語言的關鍵字,因此是內建特性。Lock是一個類,通過這個類可以實現同步訪問;
    c)在併發量比較小的情況下,使用synchronized是個不錯的選擇,但是在併發量比較高的情況下,其效能下降很嚴重,此時Lock是個不錯的方案。
    d)使用Lock的時候,等待/通知 是使用的Condition物件的await()/signal()/signalAll() ,而使用synchronized的時候,則是物件的wait()/notify()/notifyAll();由此可以看出,使用Lock的時候,粒度更細了,一個Lock可以對應多個Condition。
    e)雖然Lock缺少了synchronized隱式獲取釋放鎖的便捷性,但是卻擁有了鎖獲取與是釋放的可操作性、可中斷的獲取鎖以及超時獲取鎖等多種synchronized所不具備的同步特性;
  15. 兩個程序同時要求寫或者讀,能不能實現?如何防止程序的同步?
  16. 執行緒間操作List
  17. Java中物件的生命週期
    1)建立階段(Created)
    2)應用階段(In Use)
    3)不可見階段(Invisible)
    4)不可達階段(Unreachable)
    5)收集階段(Collected)
    6)終結階段(Finalized)
    7)物件空間重分配階段(De-allocated)
  18. Synchronized用法
    1)修飾一個程式碼塊,被修飾的程式碼塊稱為同步語句塊,其作用的範圍是大括號{}括起來的程式碼,作用的物件是呼叫這個程式碼塊的物件;
    2)修飾一個方法,被修飾的方法稱為同步方法,其作用的範圍是整個方法,作用的物件是呼叫這個方法的物件;
  19. synchronize的原理
    synchronized可以保證方法或者程式碼塊在執行時,同一時刻只有一個方法可以進入到臨界區,同時它還可以保證共享變數的記憶體可見性
    談談對Synchronized關鍵字,類鎖,方法鎖,重入鎖的理解
    static synchronized 方法的多執行緒訪問和作用
    我們知道,當synchronized修飾一個static方法時,多執行緒下,獲取的是類鎖(即Class本身,注意:不是例項);
    當synchronized修飾一個非static方法時,多執行緒下,獲取的是物件鎖(即類的例項物件)
    同一個類裡面兩個synchronized方法,兩個執行緒同時訪問的問題
  20. volatile的原理
    將當前處理器快取行的資料會寫回到系統記憶體。
    這個寫回記憶體的操作會引起在其他CPU裡快取了該記憶體地址的資料無效
  21. 談談volatile關鍵字的用法
    一般用於變數的修飾
  22. 談談volatile關鍵字的作用
    特殊域變數,volatile,注意不能修飾final的變數.
    a)volatile關鍵字為域變數的訪問提供了一種免鎖機制
    b)使用volatile修飾域相當於告訴虛擬機器該域可能會被其他執行緒更新
    c)因此每次使用該域就要重新計算,而不是使用暫存器中的值
    d)volatile不會提供任何原子操作,它也不能用來修飾final型別的變數
  23. 談談NIO的理解
    最近大概看了ZooKeeper和Mina的原始碼發現都是用Java NIO實現的,所以有必要搞清楚什麼是NIO。下面是我結合網路資料自己總結的,為了節約時間圖示隨便畫的,能達意就行。
    簡介:
    BIO:同步阻塞式IO,伺服器實現模式為一個連線一個執行緒,即客戶端有連線請求時伺服器端就需要啟動一個執行緒進行處理,如果這個連線不做任何事情會造成不必要的執行緒開銷,當然可以通過執行緒池機制改善。
    NIO:同步非阻塞式IO,伺服器實現模式為一個請求一個執行緒,即客戶端傳送的連線請求都會註冊到多路複用器上,多路複用器輪詢到連線有I/O請求時才啟動一個執行緒進行處理。
    AIO(NIO.2):非同步非阻塞式IO,伺服器實現模式為一個有效請求一個執行緒,客戶端的I/O請求都是由OS先完成了再通知伺服器應用去啟動執行緒進行處理。
    BIO
    同步阻塞式IO,相信每一個學習過作業系統網路程式設計或者任何語言的網路程式設計的人都很熟悉,在while迴圈中服務端會呼叫accept方法等待接收客戶端的連線請求,一旦接收到一個連線請求,就可以建立通訊套接字在這個通訊套接字上進行讀寫操作,此時不能再接收其他客戶端連線請求,只能等待同當前連線的客戶端的操作執行完成。
    如果BIO要能夠同時處理多個客戶端請求,就必須使用多執行緒,即每次accept阻塞等待來自客戶端請求,一旦受到連線請求就建立通訊套接字同時開啟一個新的執行緒來處理這個套接字的資料讀寫請求,然後立刻又繼續accept等待其他客戶端連線請求,即為每一個客戶端連線請求都建立一個執行緒來單獨處理,大概原理圖就像這樣:
    這裡寫圖片描述
    NIO
    同步非阻塞式IO,關鍵是採用了事件驅動的思想來實現了一個多路轉換器。
    NIO與BIO最大的區別就是隻需要開啟一個執行緒就可以處理來自多個客戶端的IO事件,這是怎麼做到的呢?
    就是多路複用器,可以監聽來自多個客戶端的IO事件:
    A. 若服務端監聽到客戶端連線請求,便為其建立通訊套接字(java中就是通道),然後返回繼續監聽,若同時有多個客戶端連線請求到來也可以全部收到,依次為它們都建立通訊套接字。
    B. 若服務端監聽到來自已經建立了通訊套接字的客戶端傳送來的資料,就會呼叫對應介面處理接收到的資料,若同時有多個客戶端發來資料也可以依次進行處理。
    C. 監聽多個客戶端的連線請求和接收資料請求同時還能監聽自己時候有資料要傳送。
    這裡寫圖片描述
    總之就是在一個執行緒中就可以呼叫多路複用介面(java中是select)阻塞同時監聽來自多個客戶端的IO請求,一旦有收到IO請求就呼叫對應函式處理。
    各自應用場景
    到這裡你也許已經發現,一旦有請求到來(不管是幾個同時到還是隻有一個到),都會呼叫對應IO處理函式處理,所以:
    (1)NIO適合處理連線數目特別多,但是連線比較短(輕操作)的場景,Jetty,Mina,ZooKeeper等都是基於java nio實現。
    (2)BIO方式適用於連線數目比較小且固定的場景,這種方式對伺服器資源要求比較高,併發侷限於應用中。
  24. synchronized 和volatile 關鍵字的區別
  25. synchronized與Lock的區別
  26. ReentrantLock 、synchronized和volatile比較
  27. ReentrantLock的內部實現
  28. lock原理
    需要實現鎖的功能,兩個必備元素,一個是表示(鎖)狀態的變數(我們假設0表示沒有執行緒獲取鎖,1表示已有執行緒佔有鎖),另一個是佇列,佇列中的節點表示因未能獲取鎖而阻塞的執行緒。為了解決多核處理器下多執行緒快取不一致的問題,表示狀態的變數必須宣告為voaltile型別,並且對錶示狀態的變數和佇列的某些操作要保證原子性和可見性
  29. Lock與synchronized的區別
    1)Lock的加鎖和解鎖都是由java程式碼配合native方法(呼叫作業系統的相關方法)實現的,而synchronize的加鎖和解鎖的過程是由JVM管理的
    2) 當一個執行緒使用synchronize獲取鎖時,若鎖被其他執行緒佔用著,那麼當前只能被阻塞,直到成功獲取鎖。而Lock則提供超時鎖和可中斷等更加靈活的方式,在未能獲取鎖的 條件下提供一種退出的機制。
    3) 一個鎖內部可以有多個Condition例項,即有多路條件佇列,而synchronize只有一路條件佇列;同樣Condition也提供靈活的阻塞方式,在未獲得通知之前可以通過中斷執行緒以 及設定等待時限等方式退出條件佇列。
    4) synchronize對執行緒的同步僅提供獨佔模式,而Lock即可以提供獨佔模式,也可以提供共享模式
  30. 死鎖的四個必要條件?
    1) 互斥條件:一個資源每次只能被一個程序使用。
    2) 請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放。
    3) 不剝奪條件:程序已獲得的資源,在末使用完之前,不能強行剝奪。
    4) 迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。
    這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之
    一不滿足,就不會發生死鎖。
  31. 怎麼避免死鎖?
    打破上述3種情況同時出現的:避免同一時刻持有兩把鎖,在可能的情況下改為先持有A,釋放後再申請B。如果上述情況無法避免,確保會被同時持有的鎖的申請順序和釋放順序在任何地方都一致。允許出現死鎖,當檢測到死鎖後觸發解鎖機制:例如申請到A後,再申請B,500ms後發現申請失敗,回頭去釋放A,解除死鎖。避免使用鎖,
  32. 物件鎖和類鎖是否會互相影響?
    1.類鎖和物件鎖不是同1個東西,一個是類的Class物件的鎖,一個是類的例項的鎖。也就是說:1個執行緒訪問靜態synchronized的時候,允許另一個執行緒訪問物件的例項synchronized方法。反過來也是成立的,因為他們需要的鎖是不同的。
    物件鎖:Java的所有物件都含有1個互斥鎖,這個鎖由JVM自動獲取和釋放。執行緒進入synchronized方法的時候獲取該物件的鎖,當然如果已經有執行緒獲取了這個物件的鎖,那麼當前執行緒會等待;synchronized方法正常返回或者拋異常而終止,JVM會自動釋放物件鎖。這裡也體現了用synchronized來加鎖的1個好處,方法拋異常的時候,鎖仍然可以由JVM來自動釋放。
    類鎖:物件鎖是用來控制例項方法之間的同步,類鎖是用來控制靜態方法(或靜態變數互斥體)之間的同步。其實類鎖只是一個概念上的東西,並不是真實存在的,它只是用來幫助我們理解鎖定例項方法和靜態方法的區別的。我們都知道,java類可能會有很多個物件,但是隻有1個Class物件,也就是說類的不同例項之間共享該類的Class物件。Class物件其實也僅僅是1個java物件,只不過有點特殊而已。由於每個java物件都有1個互斥鎖,而類的靜態方法是需要Class物件。所以所謂的類鎖,不過是Class物件的鎖而已。獲取類的Class物件有好幾種,最簡單的就是MyClass.class的方式。
  33. 什麼是執行緒池,如何使用?
    多執行緒技術主要解決處理器單元內多個執行緒執行的問題,它可以顯著減少處理器單元的閒置時間,增加處理器單元的吞吐能力。
    如果:建立執行緒時間+ 銷燬執行緒時間 >遠大線上程中執行任務的時間,則可以採用執行緒池,以提高伺服器效能。
    一個執行緒池包括以下四個基本組成部分:
    1、執行緒池管理器(ThreadPool):用於建立並管理執行緒池,包括 建立執行緒池,銷燬執行緒池,新增新任務;
    2、工作執行緒(PoolWorker):執行緒池中執行緒,在沒有任務時處於等待狀態,可以迴圈的執行任務;
    3、任務介面(Task):每個任務必須實現的介面,以供工作執行緒排程任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等;
    4、任務佇列(taskQueue):用於存放沒有處理的任務。提供一種緩衝機制。
  34. Java的併發、多執行緒、執行緒模型
    1)之後發展到多工階段,計算機能在同一時間點並行執行多工或多程序。雖然並不是真正意義上的“同一時間點”,而是多個任務或程序共享一個CPU,並交由作業系統來完成多工間對CPU的執行切換,以使得每個任務都有機會獲得一定的時間片執行。
    2)多執行緒比多工更加有挑戰。多執行緒是在同一個程式內部並行執行,因此會對相同的記憶體空間進行併發讀寫操作。這可能是在單執行緒程式中從來不會遇到的問題。然而,更現代的計算機伴隨著多核CPU的出現,也就意味著不同的執行緒能被不同的CPU核得到真正意義的並行執行。
  35. 談談對多執行緒的理解
    這裡面至少存在兩條程式,一條是主執行緒main,另外一條就是垃圾回收執行緒,即JVM一遍”執行”main,”一邊”也在執行垃圾回收機制,所以說java支援多執行緒,而多執行緒的意義它可以讓程式在一個時間段執行多個事情,提高了應用程式的使用率;
    比如上面那個例子,如果是單執行緒,那麼JVM不得不執行一會main執行緒然後停下來去執行垃圾回收機制
  36. 多執行緒有什麼要注意的問題?
    1.執行緒使用中要注意,如何控制執行緒的排程和阻塞,例如利用事件的觸發來控制執行緒的排程,也有用訊息來控制的。
    2.執行緒中如果用到公共資源,一定要考慮公共資源的執行緒安全性。一般用LOCK鎖機制來控制執行緒安全性。一定要保證不要有死鎖機制。
  37. 談談你對併發程式設計的理解並舉例說明
    可以說多執行緒程式設計帶來的影響有利有弊,好處自然是提高處理器的利用率,加快任務執行速度,弊端是執行緒安全問題。
    1)如果存在可變的成員變數,不論是基礎資料型別還是引用型別,那麼都是需要關注它的執行緒安全問題
    2)如果存在併發寫的情況,那麼修改它的時候需要加鎖。區域性變數一般情況下訪問是不需要加鎖的,因為它是棧封閉的,多執行緒不會併發訪問到。
    區域性變數如果是基礎資料型別,而非引用型別,那麼一定執行緒安全的,因為傳參是使用拷貝的方式,修改它不會影響成員變數。
  38. 談談你對多執行緒同步機制的理解?
    多執行緒技術被設計出來是為了充分利用多核cpu的優勢,讓cpu得到充分利用。
    但多執行緒有一個問題:執行緒之間是可以共享資源的,如果多個程序都在讀寫同一個資源,就會出現問題,最簡單的就是加鎖!保證執行緒的安全性,保持資料的同步。
  39. 如何保證多執行緒讀寫檔案的安全?
    同步鎖,保證執行緒的安全性和資料同步!基本上多執行緒的原理就是這樣,其實也很簡單
  40. 多執行緒斷點續傳原理斷點續傳的實現
    那麼我們接著說斷點續傳,斷點續傳其實也很簡單,原理就是使用資料庫儲存上次每個執行緒下載的位置和長度
    例如我開了兩個執行緒T1,T2來下載一個檔案,設檔案總大小為1024M,那麼就是每個執行緒下載512M
    可是我的下載中斷了,那麼我下次啟動執行緒的時候(繼續下載),是不是應該要知道,我原來下載了多少呢
    所以是這樣的,我每下載一點,就更新資料庫的資料,
    例如T1,下載了100M,就要實時更新資料庫,記錄下100M,並且記錄下這個執行緒開始下載位置(startPos),還有執行緒負責的長度(512M)
    那麼我繼續下載的時候,就可以像伺服器請求startPos+1000M開始的資料了,然後在檔案裡面也是seek(startPos+1000M)的位置繼續下載,就可以實現斷點續傳了
    繼續讀出,把檔案返回給客戶端。 當然為了下載的更快一下,也可以多執行緒下載,那麼基本實現就是給每個執行緒分配固定的位元組的檔案,分別去讀

(五)併發程式設計有關知識點

(這個是一般Android開發用的少的,所以建議多去看看):
平時Android開發中對併發程式設計可以做得比較少,Thread這個類經常會用到,但是我們想提升自己的話,一定不能停留在表面,,我們也應該去了解一下java的關於執行緒相關的原始碼級別的東西。
學習的參考資料如下:
Java 記憶體模型
java執行緒安全總結
http://www.iteye.com/topic/806990
深入理解java記憶體模型系列文章
http://ifeve.com/java-memory-model-0/
執行緒狀態:
一張圖讓你看懂JAVA執行緒間的狀態轉換
https://my.oschina.net/mingdongcheng/blog/139263
鎖:
鎖機制:synchronized、Lock、Condition
http://blog.csdn.net/vking_wang/article/details/9952063
Java 中的鎖
http://wiki.jikexueyuan.com/project/java-concurrent/locks-in-java.html
併發程式設計:
Java併發程式設計:Thread類的使用
http://www.cnblogs.com/dolphin0520/p/3920357.html
Java多執行緒程式設計總結
http://blog.51cto.com/lavasoft/27069
Java併發程式設計的總結與思考
https://www.jianshu.com/p/053943a425c3#
Java併發程式設計實戰—–synchronized
http://www.cnblogs.com/chenssy/p/4701027.html
深入分析ConcurrentHashMap
http://www.infoq.com/cn/articles/ConcurrentHashMap#


Android面試題
Android面試題包括Android基礎,還有一些原始碼級別的、原理這些等。所以想去大公司面試,一定要多看看原始碼和實現方式,常用框架可以試試自己能不能手寫實現一下,鍛鍊一下自己。
(一)Android基礎知識點

  1. 四大元件是什麼
    Activity、Service、Broadcast Receiver、Content Provider
  2. 四大元件的生命週期和簡單用法
    1)Activity
    這裡寫圖片描述
    2)Service
    這裡寫圖片描述
    3)Broadcast Receiver
    廣播分為動態註冊靜態註冊,主要是負責時間訊息的通知,舉個簡單的例子,當手機wifi開啟的時候,會有廣播通知,這個時候我們可以做許可權的申請。
    (1)動態註冊 使用IntentFilter
    MyReceiver myReceiver = new MyReceiver();
    IntentFilter intentFilter =new IntentFilter();
    intentFilter.addAction(“com.test”);
    registerReceiver(myReceiver,intentFilter);
    注意:動態註冊方式的BroadcastReceiver,生命週期僅限於當前註冊的activity,離開activity一定要解除註冊,否則就會丟擲非常熟悉的錯誤,但是這個錯誤不會導致app崩潰。
    (2)靜態註冊在AndroidManifest.xml檔案中進行配置:
    靜態註冊的BroadcastReceiver,生命週期不僅侷限於activity,對比動態註冊,進行了測試,發現activity關閉與否,不受影響,即使app退出了還是會收到廣播,意思就是說如何使通過標籤進行靜態註冊receiver,會在執行完onReceive方法後任意時間段內進行銷燬,所以我們不用手動進行取消註冊操作。
    4)Content Provider
    ContentProvider作為Android四大元件之一,並沒有Activity那樣複雜的生命週期,只有簡單地onCreate過程。ContentProvider是一個抽象類,當實現自己的ContentProvider類,只需繼承於ContentProvider,
    。對於資料的使用者來說,無需知曉資料的來源是資料庫、檔案,或者網路,只需簡單地使用ContentProvider提供的資料操作介面,也就是增(insert)、刪(delete)、改(update)、查(query)四個過程。
  3. Activity之間的通訊方式
    1)Intent
    2)藉助類的靜態變數
    3)藉助全域性變數/Application
    3)藉助外部工具
    – 藉助SharedPreference
    – 使用Android資料庫SQLite
    – 赤裸裸的使用File
    4)藉助Service
  4. Activity各種情況下的生命週期
    橫豎屏切換的時候,Activity 各種情況下的生命週期
    剛剛啟動Activity的時候:
    Activity1—–>onCreate
    Activity1—–>onStart
    Activity1—–>onResume
    由豎屏切換到橫屏(由橫屏切換到豎屏):
    Activity1—–>onPause
    Activity1—–>onSaveInstanceState
    Activity1—–>onStop
    Activity1—–>onDestroy
    Activity1—–>onCreate
    Activity1—–>onStart
    Activity1—–>onRestoreInstanceState
    Activity1—–>onResume
  5. Activity與Fragment之間生命週期比較
    這裡寫圖片描述
  6. 兩個Activity 之間跳轉時必然會執行的是哪幾個方法?
    一般情況下比如說有兩個activity,分別叫A,B。
    當在A 裡面啟用B 元件的時候, A會呼叫onPause()方法,然後B呼叫onCreate() ,onStart(), onResume()。
    這個時候B覆蓋了A的窗體, A會呼叫onStop()方法。
    如果B是個透明的視窗,或者是對話方塊的樣式, 就不會呼叫A的onStop()方法。
    如果B已經存在於Activity棧中,B就不會呼叫onCreate()方法。
    前臺切換到後臺,然後再回到前臺,Activity生命週期回撥方法。彈出Dialog,生命值週期回撥方法。
    前後臺切換(onPause—>onStop ===> onStart–>onResume)
    彈出Dialog(onPause ===> onResume)
  7. Activity的四種啟動模式對比
    Standard、singleTop、singleTask、singleInstance
    1)Standard—標準
    這個模式是預設的啟動模式,即標準模式,在不指定啟動模式的前提下,系統預設使用該模式啟動Activity,每次啟動一個Activity都會重寫建立一個新的例項,不管這個例項存不存在,
    2)singleTop–棧頂複用模式
    這個模式下,如果新的activity已經位於棧頂,那麼這個Activity不會被重寫建立,同時它的onNewIntent方法會被呼叫,通過此方法的引數我們可以去除當前請求的資訊。如果棧頂不存在該Activity的例項,則情況與standard模式相同。需要注意的是這個Activity它的onCreate(),onStart()方法不會被呼叫,因為它並沒有發生改變。
    1.當前棧中已有該Activity的例項並且該例項位於棧頂時,不會新建例項,而是複用棧頂的例項,並且會將Intent物件傳入,回撥onNewIntent方法
    2.當前棧中已有該Activity的例項但是該例項不在棧頂時,其行為和standard啟動模式一樣,依然會建立一個新的例項
    3.當前棧中不存在該Activity的例項時,其行為同standard啟動模式
    3)singleTask
    這個模式十分複雜,有各式各樣的組合。在這個模式下,如果棧中存在這個Activity的例項就會複用這個Activity,不管它是否位於棧頂,複用時,會將它上面的Activity全部出棧,並且會回撥該例項的onNewIntent方法。其實這個過程還存在一個任務棧的匹配,因為這個模式啟動時,會在自己需要的任務棧中尋找例項,如果這個任務棧不存在,則會建立這個任務棧。
    4)singleInstance
    該模式具備singleTask模