1、java面試題(基礎+進階)(必須)
1)、java中==和equals和hashCode的區別
==是運算符,用來比較兩個值、兩個對象的內存地址是否相等;
equals是Object類的方法,默認狀況下比較兩個對象是不是同一個對象,內部實現是經過「==」來實現的。
若是想比較兩個對象的其餘內容,則能夠經過重寫equals方法,
hashCoed也是Object類裏面的方法,返回值是一個對象的哈希碼,同一個對象哈希碼必定相等,但不一樣對象哈希碼也有可能相等。
一、若是兩個對象equals,Java運行時環境會認爲他們的hashcode必定相等。
二、若是兩個對象不equals,他們的hashcode有可能相等。
三、若是兩個對象hashcode相等,他們不必定equals。
四、若是兩個對象hashcode不相等,他們必定不equals。html
2)、int、char、long各佔多少字節數(筆試題多出現)
Int:4字節 chat:2字節 long\double:8字節java
3)、int與integer的區別 (筆試)
一、Integer是int的包裝類,int則是java的一種基本數據類型
二、Integer變量必須實例化後才能使用,而int變量不須要
三、Integer實際是對象的引用,當new一個Integer時,其實是生成一個指針指向此對象;而int則是直接存儲數據值
四、Integer的默認值是null,int的默認值是0android
4)、談談對java多態的理解
多態是指:父類引用指向子類對象,在執行期間判斷所引用對象的實際類型,根據其實際的類型調用其相應的方法。(同一消息能夠根據發送對象的不一樣而採用多種不一樣的行爲方式。程序員
多態的做用:消除類型之間的耦合關係。web
實現多態的技術稱爲:動態綁定(dynamic binding),是指在執行期間判斷所引用對象的實際類型,根據其實際的類型調用其相應的方法。面試
實現多態的三要素:繼承,重寫,父類引用指向子類對象(即,聲明是父類,實際指向的是子類的一個對象)算法
5)、String、StringBuffer、StringBuilder區別
一、三者在執行速度上:StringBuilder > StringBuffer > String (因爲String是常量,不可改變,拼接時會從新建立新的對象)。
二、StringBuffer是線程安全的,StringBuilder是線程不安全的。(因爲StringBuffer有緩衝區)數據庫
6)、什麼是內部類?內部類的做用
內部類:將一個類定義在另外一個類裏面或者一個方法裏面,這樣的類稱爲內部類。
做用:1.每一個內部類都能獨立的繼承一個接口的實現,因此不管外部類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響。內部類使得多繼承的解決方案變得完整,
2.方便將存在必定邏輯關係的類組織在一塊兒,又能夠對外界隱藏。
3.方便編寫事件驅動程序
4.方便編寫線程代碼設計模式
7)、抽象類和接口區別
相同:
一、都能被繼承
二、繼承的類都必須將未實現的函數實現
三、只關注方法的定義,不關注方法的實現
差別:
一、一個子類能夠繼承多個接口,可是隻能繼承一個父類
二、抽象類在對象中只能表示一種對象,接口能夠被不少對象繼承數組
8)、抽象類與接口的應用場景
若是你擁有一些方法而且想讓它們中的一些有默認實現,那麼使用抽象類吧。
若是你想實現多重繼承,那麼你必須使用接口。因爲Java不支持多繼承,子類不可以繼承多個類,但能夠實現多個接口。所以你就能夠使用接口來解決它。
若是基本功能在不斷改變,那麼就須要使用抽象類。若是不斷改變基本功能而且使用接口,那麼就須要改變全部實現了該接口的類。
9)、抽象類是否能夠沒有方法和屬性?
抽象類專用於派生出子類,子類必須實現抽象類所聲明的抽象方法,不然,子類還是抽象類。
包含抽象方法的類必定是抽象類,但抽象類中的方法不必定是抽象方法。
抽象類中能夠沒有抽象方法,但有抽象方法的必定是抽象類。因此,java中 抽象類裏面能夠沒有抽象方法。 抽象類的做用在於子類對其的繼承和實現,也就是多態;而沒有抽象方法的抽象類的存在價值在於:實例化了沒有意義,由於類已經定義好了,不能改變其中的方法體,可是實例化出來的對象卻知足不了要求,只有繼承並重寫了他的子類才能知足要求。因此才把它定義爲沒有抽象方法的抽象類
10)、泛型中extends和super的區別
一、< extends T>限定參數類型的上界:參數類型必須是T或T的子類型
限定參數類型的下界:參數類型必須是T或T的超類型
二、 只能用於方法返回,告訴編譯器此返參的類型的最小繼承邊界爲T,T和T的父類都能接收,可是入參類型沒法肯定,只能接受null的傳入
只能用於限定方法入參,告訴編譯器入參只能是T或其子類型,而返參只能用Object類接收既不能用於入參也不能用於返參
11)、父類的靜態方法可否被子類重寫
不能,父類的靜態方法可以被子類繼承,可是不可以被子類重寫,即便子類中的靜態方法與父類中的靜態方法徹底同樣,也是兩個徹底不一樣的方法。
進程和線程的區別(問的蠻多的,回答的時候用口語說出來,不要背書)
進程是cpu資源分配的最小單位,線程是cpu調度的最小單位。
進程之間不能共享資源,而線程共享所在進程的地址空間和其它資源。
一個進程內可擁有多個線程,進程可開啓進程,也可開啓線程。
一個線程只能屬於一個進程,線程可直接使用同進程的資源,線程依賴於進程而存在。
12)、final,finally,finalize的區別
final:修飾類、成員變量和成員方法,類不可被繼承,成員變量不可變,成員方法不可重寫
finally:與try...catch...共同使用,確保不管是否出現異常都能被調用到
finalize:類的方法,垃圾回收以前會調用此方法,子類能夠重寫finalize()方法實現對資源的回收
13)、Serializable 和Parcelable 的區別
Serializable Java 序列化接口 在硬盤上讀寫 讀寫過程當中有大量臨時變量的生成,內部執行大量的i/o操做,效率很低。
Parcelable Android 序列化接口 效率高 使用麻煩 在內存中讀寫(AS有相關插件 一鍵生成所需方法) ,對象不能保存到磁盤中
14)、靜態屬性和靜態方法是否能夠被繼承?是否能夠被重寫?以及緣由?
可繼承 不可重寫 而是被隱藏
若是子類裏面定義了靜態方法和屬性,那麼這時候父類的靜態方法或屬性稱之爲"隱藏"。若是你想要調用父類的靜態方法和屬性,直接經過父類名.方法或變量名完成。
15)、成員內部類、靜態內部類、局部內部類和匿名內部類的理解,以及項目中的應用
java中內部類主要分爲成員內部類、局部內部類(嵌套在方法和做用域內)、匿名內部類(沒構造方法)、靜態內部類(static修飾的類,不能使用任何外圍類的非static成員變量和方法, 不依賴外圍類)
使用內部類最吸引人的緣由是:每一個內部類都能獨立地繼承一個(接口的)實現,因此不管外圍類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響。
由於Java不支持多繼承,支持實現多個接口。但有時候會存在一些使用接口很難解決的問題,這個時候咱們能夠利用內部類提供的、能夠繼承多個具體的或者抽象的類的能力來解決這些程序設計問題。能夠這樣說,接口只是解決了部分問題,而內部類使得多重繼承的解決方案變得更加完整。
16)、string 轉換成 integer的方式及原理
String —>integer Intrger.parseInt(string);
Integer—> string Integer.toString();
原理:
parseInt(String s)--內部調用parseInt(s,10)(默認爲10進制)
正常判斷null,進制範圍,length等
判斷第一個字符是不是符號位
循環遍歷肯定每一個字符的十進制值
經過*= 和-= 進行計算拼接
判斷是否爲負值 返回結果。
17)、哪些狀況下的對象會被垃圾回收機制處理掉?
1.全部實例都沒有活動線程訪問。
2.沒有被其餘任何實例訪問的循環引用實例。
3.Java 中有不一樣的引用類型。判斷實例是否符合垃圾收集的條件都依賴於它的引用類型。
18)、要判斷怎樣的對象是沒用的對象。這裏有2種方法:
1.採用標記計數的方法:
給內存中的對象給打上標記,對象被引用一次,計數就加1,引用被釋放了,計數就減一,當這個計數爲0的時候,這個對象就能夠被回收了。固然,這也就引起了一個問題:循環引用的對象是沒法被識別出來而且被回收的。因此就有了第二種方法:
2.採用根搜索算法:
從一個根出發,搜索全部的可達對象,這樣剩下的那些對象就是須要被回收的
19)、靜態代理和動態代理的區別,什麼場景使用?
由程序員建立或由特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。動態代理類:在程序運行時,運用反射機制動態建立而成。
場景:著名的Spring框架、Hibernate框架等等都是動態代理的使用例子
20)、Java的異常體系
Throwable,Error,Exception
21)、談談你對解析與分派的認識。
解析:Java中方法調用的目標方法在Class文件裏面都是常量池中的符號引用,在類加載的解析階段,會將其中的一部分符號引用轉化爲直接引用。這種解析的前提是:方法在程序真正運行以前就有一個能夠肯定的調用版本,而且這個方法的調用版本在運行期是不可改變的,即「編譯期可知,運行期不可變」,這類目標的方法的調用稱爲解析(Resolve)。
只要能被invokestatic和invokespecial指令調用的方法,均可以在解析階段中肯定惟一的調用版本,符合條件的有靜態方法(invokestatic指令)、私有方法、實例構造方法、父類方法(這3個是invokespecial指令),它們在類加載的的解析階段就會將符號引用解析爲該方法的直接引用。
分派:分派是多態性的體現,Java虛擬機底層提供了咱們開發中「重載」(Overload)「和重寫」(Override)的底層實現。其中重載屬於靜態分派,而重寫則是動態分派的過程。
解析調用必定是個靜態的過程,在編譯期就徹底肯定,在類加載的解析階段就將涉及的符號引用所有轉變爲能夠肯定的直接引用,不會延遲到運行期再去完成。
22)、Java中實現多態的機制是什麼?
答:方法的重寫Overriding和重載Overloading是Java多態性的不一樣表現
重寫Overriding是父類與子類之間多態性的一種表現
重載Overloading是一個類中多態性的一種表現.
23)、說說你對Java反射的理解
JAVA反射機制是在運行狀態中, 對於任意一個類, 都可以知道這個類的全部屬性和方法; 對於任意一個對象, 都可以調用它的任意一個方法和屬性。 從對象出發,經過反射(Class類)能夠取得取得類的完整信息(類名 Class類型,所在包、具備的全部方法 Method[]類型、某個方法的完整信息(包括修飾符、返回值類型、異常、參數類型)、全部屬性 Field[]、某個屬性的完整信息、構造器 Constructors),調用類的屬性或方法本身的總結: 在運行過程當中得到類、對象、方法的全部信息。
24)、說說你對Java註解的理解
元註解
元註解的做用就是負責註解其餘註解。java5.0的時候,定義了4個標準的meta-annotation類型,它們用來提供對其餘註解的類型做說明。
1.@Target
2.@Retention
3.@Documented
4.@Inherited
25)、Java中String的瞭解
在源碼中string是用final 進行修飾,它是不可更改,不可繼承的常量。
26)、String爲何要設計成不可變的?
一、字符串池的需求
字符串池是方法區(Method Area)中的一塊特殊的存儲區域。當一個字符串已經被建立而且該字符串在 池 中,該字符串的引用會當即返回給變量,而不是從新建立一個字符串再將引用返回給變量。若是字符串不是不可變的,那麼改變一個引用(如: string2)的字符串將會致使另外一個引用(如: string1)出現髒數據。
二、容許字符串緩存哈希碼
在java中經常會用到字符串的哈希碼,例如: HashMap 。String的不變性保證哈希碼始終一,所以,他能夠不用擔憂變化的出現。 這種方法意味着沒必要每次使用時都從新計算一次哈希碼——這樣,效率會高不少。
三、安全
String普遍的用於java 類中的參數,如:網絡鏈接(Network connetion),打開文件(opening files )等等。若是String不是不可變的,網絡鏈接、文件將會被改變——這將會致使一系列的安全威脅。操做的方法本覺得鏈接上了一臺機器,但實際上卻不是。因爲反射中的參數都是字符串,一樣,也會引發一系列的安全問題。
27)、Object類的equal和hashCode方法重寫,爲何?
首先equals與hashcode間的關係是這樣的:
一、若是兩個對象相同(即用equals比較返回true),那麼它們的hashCode值必定要相同;
二、若是兩個對象的hashCode相同,它們並不必定相同(即用equals比較返回false)
因爲爲了提升程序的效率才實現了hashcode方法,先進行hashcode的比較,若是不一樣,那沒就沒必要在進行equals的比較了,這樣就大大減小了equals比較的次數,這對比須要比較的數量很大的效率提升是很明顯的
28)、java的集合以及集合之間的繼承關係
List,Set,Map的區別
Set是最簡單的一種集合。集合中的對象不按特定的方式排序,而且沒有重複對象。 Set接口主要實現了兩個實現類:HashSet: HashSet類按照哈希算法來存取集合中的對象,存取速度比較快
TreeSet :TreeSet類實現了SortedSet接口,可以對集合中的對象進行排序。
List的特徵是其元素以線性方式存儲,集合中能夠存放重複對象。
ArrayList() : 表明長度能夠改變得數組。能夠對元素進行隨機的訪問,向ArrayList()中插入與刪除元素的速度慢。
LinkedList(): 在實現中採用鏈表數據結構。插入和刪除速度快,訪問速度慢。
Map 是一種把鍵對象和值對象映射的集合,它的每個元素都包含一對鍵對象和值對象。 Map沒有繼承於Collection接口 從Map集合中檢索元素時,只要給出鍵對象,就會返回對應的值對象。
HashMap:Map基於散列表的實現。插入和查詢「鍵值對」的開銷是固定的。能夠經過構造器設置容量capacity和負載因子load factor,以調整容器的性能。
LinkedHashMap: 相似於HashMap,可是迭代遍歷它時,取得「鍵值對」的順序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一點。而在迭代訪問時發而更快,由於它使用鏈表維護內部次序。
TreeMap : 基於紅黑樹數據結構的實現。查看「鍵」或「鍵值對」時,它們會被排序(次序由Comparabel或Comparator決定)。TreeMap的特色在 於,你獲得的結果是通過排序的。TreeMap是惟一的帶有subMap()方法的Map,它能夠返回一個子樹。
WeakHashMao :弱鍵(weak key)Map,Map中使用的對象也被容許釋放: 這是爲解決特殊問題設計的。若是沒有map以外的引用指向某個「鍵」,則此「鍵」能夠被垃圾收集器回收。
List和Set和Map的實現方式以及存儲方式
List:
經常使用實現方式有:ArrayList和LinkedList
ArrayList 的存儲方式:數組,查詢快
LinkedList的存儲方式:鏈表,插入,刪除快
Set:
經常使用實現方式有:HashSet和TreeSet
HashSet的存儲方式:哈希碼算法,加入的對象須要實現hashcode()方法,快速查找元素
TreeSet的存儲方式:按序存放,想要有序就要實現Comparable接口
附加:
集合框架提供了2個實用類:collections(排序,複製、查找)和Arrays對數組進行(排序,複製、查找)
Map:
經常使用實現方式有:HashMap和TreeMap
HashMap的存儲方式:哈希碼算法,快速查找鍵值
TreeMap存儲方式:對鍵按序存放
29)、數組(如arryList)中數組容量不夠了,怎麼擴容?
在JDK1.7中若是經過無參構造的話,初始數組容量是0,當數組進行add()添加時,才真正的分配容量,經過位運算,每次按照1.5倍的比例擴容。
在JDK1.6中,初始數組容量爲10,每次經過cope of方式擴容1.5倍+1.
HashMap的實現原理,如何put數據和get數據?
在JDK1.6,JDK1.7中,HashMap採用數組+鏈表實現,即便用鏈表處理衝突,同一hash值的鏈表都存儲在一個鏈表裏。可是當位於一個鏈表中的元素較多,即hash值相等的元素較多時,經過key值依次查找的效率較低。而JDK1.8中,HashMap採用位數組+鏈表+紅黑樹實現,當鏈表長度超過閾值(8)時,將鏈表轉換爲紅黑樹,這樣大大減小了查找時間。
當鏈表數組的容量超過初始容量*加載因子(默認0.75)時,再散列將鏈表數組擴大2倍,把原鏈表數組的搬移到新的數組中。爲何須要使用加載因子?爲何須要擴容呢?由於若是填充比很大,說明利用的空間不少,若是一直不進行擴容的話,鏈表就會愈來愈長,這樣查找的效率很低,擴容以後,將原來鏈表數組的每個鏈表分紅奇偶兩個子鏈表分別掛在新鏈表數組的散列位置,這樣就減小了每一個鏈表的長度,增長查找效率。
HashMap在put時候,底層源碼能夠看出,當程序試圖將一個key-value對象放入到HashMap中,首先根據該key的hashCode()返回值決定該Entry的存儲位置,若是兩個Entry的key的hashCode()方法返回值相同,那他們的存儲位置相同,若是這兩個Entry的key經過equals比較返回true,新添加的Entry的value將會覆蓋原來的Entry的value,可是key不會被覆蓋,反之,若是返回false,新添加的Entry將與集合中原有的Entry造成Entry鏈,新添加的位於頭部,舊的位於尾部。
存:
取:
30)、ArrayMap和HashMap的對比
一、存儲方式不一樣
HashMap內部有一個HashMapEntry[]對象,每個鍵值對都存儲在這個對象裏,當使用put方法添加鍵值對時,就會new一個HashMapEntry對象,
二、添加數據時擴容時的處理不同,進行了new操做,從新建立對象,開銷很大。ArrayMap用的是copy數據,因此效率相對要高。
三、ArrayMap提供了數組收縮的功能,在clear或remove後,會從新收縮數組,是否空間
四、ArrayMap採用二分法查找;
31)、List,Set,Map的區別
Set是最簡單的一種集合。集合中的對象不按特定的方式排序,而且沒有重複對象。 Set接口主要實現了兩個實現類:HashSet: HashSet類按照哈希算法來存取集合中的對象,存取速度比較快
TreeSet :TreeSet類實現了SortedSet接口,可以對集合中的對象進行排序。
List的特徵是其元素以線性方式存儲,集合中能夠存放重複對象。
ArrayList() : 表明長度能夠改變得數組。能夠對元素進行隨機的訪問,向ArrayList()中插入與刪除元素的速度慢。
LinkedList(): 在實現中採用鏈表數據結構。插入和刪除速度快,訪問速度慢。
Map 是一種把鍵對象和值對象映射的集合,它的每個元素都包含一對鍵對象和值對象。 Map沒有繼承於Collection接口 從Map集合中檢索元素時,只要給出鍵對象,就會返回對應的值對象。
HashMap:Map基於散列表的實現。插入和查詢「鍵值對」的開銷是固定的。能夠經過構造器設置容量capacity和負載因子load factor,以調整容器的性能。
LinkedHashMap: 相似於HashMap,可是迭代遍歷它時,取得「鍵值對」的順序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一點。而在迭代訪問時發而更快,由於它使用鏈表維護內部次序。
TreeMap : 基於紅黑樹數據結構的實現。查看「鍵」或「鍵值對」時,它們會被排序(次序由Comparabel或Comparator決定)。TreeMap的特色在 於,你獲得的結果是通過排序的。TreeMap是惟一的帶有subMap()方法的Map,它能夠返回一個子樹。
WeakHashMap :弱鍵(weak key)Map,Map中使用的對象也被容許釋放: 這是爲解決特殊問題設計的。若是沒有map以外的引用指向某個「鍵」,則此「鍵」能夠被垃圾收集器回收。
32)、HashMap和HashTable的區別
HashMap容許key和value爲null;
HashMap是非同步的,線程不安全,也能夠經過Collections.synchronizedMap()方法來獲得一個同步的HashMap
HashMap存取速度更快,效率高
HashMap去掉了HashTable中的contains方法,加上了containsValue和containsKey方法
33)、HashMap與HashSet的區別
HashSet與HashMap怎麼判斷集合元素重複?
HashSet不能添加劇復的元素,當調用add(Object)方法時候,
首先會調用Object的hashCode方法判hashCode是否已經存在,如不存在則直接插入元素;若是已存在則調用Object對象的equals方法判斷是否返回true,若是爲true則說明元素已經存在,如爲false則插入元素。
集合Set實現Hash怎麼防止碰撞
重寫hashcode()和equles()方法
ArrayList和LinkedList的區別,以及應用場景
ArrayList是基於數組實現的,ArrayList線程不安全。
LinkedList是基於雙鏈表實現的:
使用場景:
(1)若是應用程序對各個索引位置的元素進行大量的存取或刪除操做,ArrayList對象要遠優於LinkedList對象;
( 2 ) 若是應用程序主要是對列表進行循環,而且循環時候進行插入或者刪除操做,LinkedList對象要遠優於ArrayList對象;
34)、數組和鏈表的區別
數組:是將元素在內存中連續存儲的;它的優勢:由於數據是連續存儲的,內存地址連續,因此在查找數據的時候效率比較高;它的缺點:在存儲以前,咱們須要申請一塊連續的內存空間,而且在編譯的時候就必須肯定好它的空間的大小。在運行的時候空間的大小是沒法隨着你的須要進行增長和減小而改變的,當數據兩比較大的時候,有可能會出現越界的狀況,數據比較小的時候,又有可能會浪費掉內存空間。在改變數據個數時,增長、插入、刪除數據效率比較低。
鏈表:是動態申請內存空間,不須要像數組須要提早申請好內存的大小,鏈表只需在用的時候申請就能夠,根據須要來動態申請或者刪除內存空間,對於數據增長和刪除以及插入比數組靈活。還有就是鏈表中數據在內存中能夠在任意的位置,經過應用來關聯數據(就是經過存在元素的指針來聯繫)
35)、堆和樹的區別
節點的順序
在二叉搜索樹中,左子節點必須比父節點小,右子節點必須必比父節點大。可是在堆中並不是如此。在最大堆中兩個子節點都必須比父節點小,而在最小堆中,它們都必須比父節點大。
內存佔用
普通樹佔用的內存空間比它們存儲的數據要多。你必須爲節點對象以及左/右子節點指針分配額外內存。堆僅僅使用一個數據來存儲數組,且不使用指針。
平衡
二叉搜索樹必須是「平衡」的狀況下,其大部分操做的複雜度才能達到O(log n)。你能夠按任意順序位置插入/刪除數據,或者使用 AVL 樹或者紅黑樹,可是在堆中實際上不須要整棵樹都是有序的。咱們只須要知足對屬性便可,因此在堆中平衡不是問題。由於堆中數據的組織方式能夠保證O(log n) 的性能。
搜索
在二叉樹中搜索會很快,可是在堆中搜索會很慢。在堆中搜索不是第一優先級,由於使用堆的目的是將最大(或者最小)的節點放在最前面,從而快速的進行相關插入、刪除操做。
36)、什麼是深拷貝和淺拷貝
淺拷貝:對基本數據類型進行值傳遞,對引用數據類型進行引用傳遞般的拷貝,此爲淺拷貝。
深拷貝:對基本數據類型進行值傳遞,對引用數據類型,建立一個新的對象,並複製其內容,此爲深拷貝。
37)、判斷單鏈表成環與否?
使用快慢指針遍歷鏈表:
慢指針:
從頭節點開始,一次跳一個節點。
快指針:
從頭節點開始,一次跳兩個節點。
若是是成環的,這兩個指針必定會相遇。
38)、開啓線程的三種方式?
java有三種建立線程的方式,分別是繼承Thread類、實現Runable接口和使用線程池
39)、線程和進程的區別?
線程是進程的子集,一個進程能夠有不少線程,每條線程並行執行不一樣的任務。不一樣的進程使用不一樣的內存空間,而全部的線程共享一片相同的內存空間。別把它和棧內存搞混,每一個線程都擁有單獨的棧內存用來存儲本地數據。
40)、爲何要有線程,而不是僅僅用進程?
線程能夠增長併發的程度啊。其實多進程也是能夠併發,可是爲何要是線程呢?由於線程是屬於進程的,是個輕量級的對象。因此再切換線程時只須要作少許的工做,而切換進程消耗很大。這是從操做系統角度講。
從用戶程序角度講,有些程序在邏輯上須要線程,好比掃雷,它須要一個線程等待用戶的輸入,另外一個線程的來更新時間。還有一個例子就是聊天程序,一個線程是響應用戶輸入,一個線程是響應對方輸入。若是沒有多線程,那麼只能你說一句我說一句,你不說我這裏就不能動,我還不能連續說。因此用戶程序有這種須要,操做系統就要提供響應的機制
41)、run()和start()方法區別
這個問題常常被問到,但仍是能今後區分出面試者對Java線程模型的理解程度。start()方法被用來啓動新建立的線程,並且start()內部調用了run()方法,這和直接調用run()方法的效果不同。當你調用run()方法的時候,只會是在原來的線程中調用,沒有新的線程啓動,start()方法纔會啓動新線程。
42)、如何控制某個方法容許併發訪問線程的個數?
semaphore.acquire() 請求一個信號量,這時候的信號量個數-1(一旦沒有可以使用的信號量,也即信號量個數變爲負數時,再次請求的時候就會阻塞,直到其餘線程釋放了信號量)
semaphore.release() 釋放一個信號量,此時信號量個數+1
43)、在Java中wait和seelp方法的不一樣
Java程序中wait 和 sleep都會形成某種形式的暫停,它們能夠知足不一樣的須要。wait()方法用於線程間通訊,若是等待條件爲真且其它線程被喚醒時它會釋放鎖,而sleep()方法僅僅釋放CPU資源或者讓當前線程中止執行一段時間,但不會釋放鎖。
44)、談談wait/notify關鍵字的理解
等待對象的同步鎖,須要得到該對象的同步鎖才能夠調用這個方法,不然編譯能夠經過,但運行時會收到一個異常:IllegalMonitorStateException。
調用任意對象的 wait() 方法致使該線程阻塞,該線程不可繼續執行,而且該對象上的鎖被釋放。
喚醒在等待該對象同步鎖的線程(只喚醒一個,若是有多個在等待),注意的是在調用此方法的時候,並不能確切的喚醒某一個等待狀態的線程,而是由JVM肯定喚醒哪一個線程,並且不是按優先級。
調用任意對象的notify()方法則致使因調用該對象的 wait()方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到得到鎖後才真正可執行)。
45)、什麼致使線程阻塞?
阻塞式方法是指程序會一直等待該方法完成期間不作其餘事情,ServerSocket的accept()方法就是一直等待客戶端鏈接。這裏的阻塞是指調用結果返回以前,當前線程會被掛起,直到獲得結果以後纔會返回。此外,還有異步和非阻塞式方法在任務完成前就返回。
46)、線程如何關閉?
一種是調用它裏面的stop()方法
另外一種就是你本身設置一箇中止線程的標記 (推薦這種)
47)、講一下java中的同步的方法(另外一種問法:數據一致性如何保證?)
1.即有synchronized關鍵字修飾的方法。
2.同步代碼塊(如:雙重判斷的單例模式)
3.使用特殊域變量(volatile)實現線程同步
4.使用重入鎖實現線程同步
5.使用局部變量實現線程同步
48)、如何保證線程安全?
1.synchronized;
2.Object方法中的wait,notify;
3.ThreadLocal機制 來實現的。
49)、如何實現線程同步?
一、synchronized關鍵字修改的方法。二、synchronized關鍵字修飾的語句塊三、使用特殊域變量(volatile)實現線程同步
50)、兩個進程同時要求寫或者讀,能不能實現?如何防止進程的同步?
能夠實現的。
同步方式有: 互斥鎖、條件變量、讀寫鎖、記錄鎖(文件鎖)和信號燈
51)、線程間操做List
List list = Collections.synchronizedList(new ArrayList());
52)、Synchronized用法及原理
用法:修飾靜態方法、實例方法、代碼塊
原理:不是一兩句話能說清,建議去深刻了解一下。
53)、談談對Synchronized關鍵字,類鎖,方法鎖,重入鎖的理解
java的對象鎖和類鎖:java的對象鎖和類鎖在鎖的概念上基本上和內置鎖是一致的,可是,兩個鎖實際是有很大的區別的,對象鎖是用於對象實例方法,或者一個對象實例上的,類鎖是用於類的靜態方法或者一個類的class對象上的。咱們知道,類的對象實例能夠有不少個,可是每一個類只有一個class對象,因此不一樣對象實例的對象鎖是互不干擾的,可是每一個類只有一個類鎖。可是有一點必須注意的是,其實類鎖只是一個概念上的東西,並非真實存在的,它只是用來幫助咱們理解鎖定實例方法和靜態方法的區別的
54)、static synchronized 方法的多線程訪問和做用
1.synchronized static是某個類的範圍,synchronized static cSync{}防止多個線程同時訪問這個類中的synchronized static 方法。它能夠對類的全部對象實例起做用。
2.synchronized 是某實例的範圍,synchronized isSync(){}防止多個線程同時訪問這個實例中的synchronized 方法。
55)、同一個類裏面兩個synchronized方法,兩個線程同時訪問的問題
同一個object中多個方法都加了synchronized關鍵字的時候,其中調用任意方法以後需等該方法執行完成才能調用其餘方法,即同步的,阻塞的;
此結論一樣適用於對於object中使用synchronized(this)同步代碼塊的場景;
synchronized鎖定的都是當前對象!
56)、volatile的做用,原理,性能。
做用:一、保持內存可見性 二、防止指令重排
原理:獲取JIT(即時Java編譯器,把字節碼解釋爲機器語言發送給處理器)的彙編代碼,發現volatile多加了lock addl指令,這個操做至關於一個內存屏障,使得lock指令後的指令不能重排序到內存屏障前的位置。這也是爲何JDK1.5之後能夠使用雙鎖檢測實現單例模式。
lock前綴的另外一層意義是使得本線程工做內存中的volatile變量值當即寫入到主內存中,而且使得其餘線程共享的該volatile變量無效化,這樣其餘線程必須從新從主內存中讀取變量值。
性能:讀操做與普通變量無差異,寫操做會慢一些,大多狀況比鎖消耗低。
57)、synchronized 和volatile 關鍵字的區別
1.volatile本質是在告訴jvm當前變量在寄存器(工做內存)中的值是不肯定的,須要從主存中讀取;synchronized則是鎖定當前變量,只有當前線程能夠訪問該變量,其餘線程被阻塞住。
2.volatile僅能使用在變量級別;synchronized則能夠使用在變量、方法、和類級別的
3.volatile僅能實現變量的修改可見性,不能保證原子性;而synchronized則能夠保證變量的修改可見性和原子性
4.volatile不會形成線程的阻塞;synchronized可能會形成線程的阻塞。
5.volatile標記的變量不會被編譯器優化;synchronized標記的變量能夠被編譯器優化
58)、synchronized與Lock的區別及使用場景
synchronized原始採用的是CPU悲觀鎖機制,即線程得到的是獨佔鎖。獨佔鎖意味着其餘線程只能依靠阻塞來等待線程釋放鎖。而在CPU轉換線程阻塞時會引發線程上下文切換,當有不少線程競爭鎖的時候,會引發CPU頻繁的上下文切換致使效率很低;
而Lock用的是樂觀鎖方式。所謂樂觀鎖就是,每次不加鎖而是假設沒有衝突而去完成某項操做,若是由於衝突失敗就重試,直到成功爲止。樂觀鎖實現的機制就是CAS操做(Compare and Swap)。咱們能夠進一步研究ReentrantLock的源代碼,會發現其中比較重要的得到鎖的一個方法是compareAndSetState。這裏其實就是調用的CPU提供的特殊指令。
使用場景:在性能上來講,若是競爭資源不激烈,二者的性能是差很少的,而當競爭資源很是激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優於synchronized。因此說,在具體使用時要根據適當狀況選擇。
59)、ReentrantLock 、synchronized和volatile比較
java在過去很長一段時間只能經過synchronized關鍵字來實現互斥,它有一些缺點。好比你不能擴展鎖以外的方法或者塊邊界,嘗試獲取鎖時不能中途取消等。Java 5 經過Lock接口提供了更復雜的控制來解決這些問題。 ReentrantLock 類實現了 Lock,它擁有與 synchronized 相同的併發性和內存語義且它還具備可擴展性。
60)、死鎖的四個必要條件?怎麼避免死鎖?
死鎖產生的緣由
61)、什麼是線程池,如何使用?
建立線程要花費昂貴的資源和時間,若是任務來了才建立線程那麼響應時間會變長,並且一個進程能建立的線程數有限。爲了不這些問題,在程序啓動的時候就建立若干線程來響應處理,它們被稱爲線程池,裏面的線程叫工做線程。從JDK1.5開始,Java API提供了Executor框架讓你能夠建立不一樣的線程池。好比單線程池,每次處理一個任務;數目固定的線程池或者是緩存線程池(一個適合不少生存期短的任務的程序的可擴展線程池)
62)、談談對多線程的理解
線程是由一個主線程和不少個子線程組成的,主線程消失,子線程也會消失,可是子線程消失其中一個主線程不會消失
線程的生命週期分爲5個步驟像人的一輩子同樣,這5個步驟分別對應了5個方法
新生-->啓動-->運行-->阻塞-->銷燬
繼承Thread類or實現runnable方法-->start-->run-->sleep(睡眠)or wait(掛起)-->destroy
63)、多線程有什麼要注意的問題?
給線程起有意義的名字,這樣方便找Bug
縮小同步範圍,從而減小鎖的爭用,例如對於 synchronized,應該儘可能使用同步塊而不是同步方法
多用同步工具少用 wait() 和 notify()。首先,CountDownLatch, CyclicBarrier, Semaphore 和Exchanger 這些同步類簡化了編碼操做,而用 wait() 和 notify() 很難實現複雜控制流;其次,這些同步類是由最好的企業編寫和維護,在後續的 JDK 中還會不斷優化和完善。
64)、使用BlockingQueue實現生產者消費者問題
多用併發集合少用同步集合,例如應該使用 ConcurrentHashMap 而不是 Hashtable
使用本地變量和不可變類來保證線程安全
使用線程池而不是直接建立線程,這是由於建立線程代價很高,線程池能夠有效地利用有限的線程來啓動任務
本身去設計網絡請求框架,怎麼作?
這種並無一個徹底正確的答案,看我的的思路與理解
65)、okhttp源碼
本身看一遍源碼便可,最好可以手寫出他的流程。
從網絡加載一個10M的圖片,說下注意事項
圖片緩存、異常恢復、質量壓縮,從這幾方面說就行了
66)、TCP的3次握手和四次揮手
三次握手:
第一次:客戶端發送請求到服務器,服務器知道客戶端發送,本身接收正常。SYN=1,seq=x
第二次:服務器發給客戶端,客戶端知道本身發送、接收正常,服務器接收、發送正常。ACK=1,ack=x+1,SYN=1,seq=y
第三次:客戶端發給服務器:服務器知道客戶端發送,接收正常,本身接收,發送也正常.seq=x+1,ACK=1,ack=y+1
四次揮手:
第一次:客戶端請求斷開FIN,seq=u
第二次:服務器確認客戶端的斷開請求ACK,ack=u+1,seq=v
第三次:服務器請求斷開FIN,seq=w,ACK,ack=u+1
第四次:客戶端確認服務器的斷開ACK,ack=w+1,seq=u+1
爲何鏈接的時候是三次握手,關閉的時候倒是四次握手?
由於當Server端收到Client端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。可是關閉鏈接時,當Server端收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四步握手。
爲何不能用兩次握手進行鏈接?
3次握手完成兩個重要的功能,既要雙方作好發送數據的準備工做(雙方都知道彼此已準備好),也要容許雙方就初始序列號進行協商,這個序列號在握手過程當中被髮送和確認。
如今把三次握手改爲僅須要兩次握手,死鎖是可能發生的。
爲何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鏈接。
TCP與UDP的區別
tcp是面向鏈接的,因爲tcp鏈接須要三次握手,因此可以最低限度的下降風險,保證鏈接的可靠性。
udp 不是面向鏈接的,udp創建鏈接前不須要與對象創建鏈接,不管是發送仍是接收,都沒有發送確認信號。因此說udp是不可靠的。
因爲udp不須要進行確認鏈接,使得UDP的開銷更小,傳輸速率更高,因此實時行更好。
67)、TCP與UDP的應用
從特色上咱們已經知道,TCP 是可靠的但傳輸速度慢 ,UDP 是不可靠的但傳輸速度快。所以在選用具體協議通訊時,應該根據通訊數據的要求而決定。
若通訊數據完整性需讓位與通訊實時性,則應該選用 TCP 協議(如文件傳輸、重要狀態的更新等);反之,則使用 UDP 協議(如視頻傳輸、實時通訊等)。
68)、Http https區別,此處延伸:https的實現原理
一、https協議須要到ca申請證書,通常免費證書較少,於是須要必定費用。
二、http是超文本傳輸協議,信息是明文傳輸,https則是具備安全性的ssl加密傳輸協議。
三、http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。
四、http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
五、https實現原理:
(1)客戶使用https的URL訪問Web服務器,要求與Web服務器創建SSL鏈接。
(2)Web服務器收到客戶端請求後,會將網站的證書信息(證書中包含公鑰)傳送一份給客戶端。
(3)客戶端的瀏覽器與Web服務器開始協商SSL鏈接的安全等級,也就是信息加密的等級。
(4)客戶端的瀏覽器根據雙方贊成的安全等級,創建會話密鑰,而後利用網站的公鑰將會話密鑰加密,並傳送給網站。
(5)Web服務器利用本身的私鑰解密出會話密鑰。
(6)Web服務器利用會話密鑰加密與客戶端之間的通訊。
七、Http位於TCP/IP模型中的第幾層?爲何說Http是可靠的數據傳輸協議?
tcp/ip的五層模型:
從下到上:物理層->數據鏈路層->網絡層->傳輸層->應用層
其中tcp/ip位於模型中的網絡層,處於同一層的還有ICMP(網絡控制信息協議)。http位於模型中的應用層
因爲tcp/ip是面向鏈接的可靠協議,而http是在傳輸層基於tcp/ip協議的,因此說http是可靠的數據傳輸協議。
八、HTTP連接的特色
HTTP鏈接最顯著的特色是客戶端發送的每次請求都須要服務器回送響應,在請求結束後,會主動釋放鏈接。
從創建鏈接到關閉鏈接的過程稱爲「一次鏈接」。
HTTP報文結構
一個HTTP請求報文由四個部分組成:請求行、請求頭部、空行、請求數據。
1.請求行
請求行由請求方法字段、URL字段和HTTP協議版本字段3個字段組成,它們用空格分隔。好比 GET /data/info.html HTTP/1.1
2.請求頭部
HTTP客戶程序(例如瀏覽器),向服務器發送請求的時候必須指明請求類型(通常是GET或者 POST)。若有必要,客戶程序還能夠選擇發送其餘的請求頭。大多數請求頭並非必需的,但Content-Length除外。對於POST請求來講 Content-Length必須出現。
3.空行
它的做用是經過一個空行,告訴服務器請求頭部到此爲止。
4.請求數據
若方法字段是GET,則此項爲空,沒有數據。若方法字段是POST,則一般來講此處放置的就是要提交的數據
HTTP與HTTPS的區別以及如何實現安全性
區別:http是明文傳輸,傳輸的數據極可能被中間節點獲取,從而致使數據傳輸不安全
https是加密傳輸,能夠保證數據的傳輸安全
如何實現:http是應用層協議,它會將要傳輸的數據以明文的方式給傳輸層,這樣顯然不安全。https則是在應用層與傳輸層之間又加了一層,該層遵照SSL/TLS協議,用於數據加密。
如何驗證證書的合法性?
一、證書是不是信任的有效證書。所謂信任:瀏覽器內置了信任的根證書,就是看看web服務器的證書是否是這些信任根發的或者信任根的二級證書機構頒發的。所謂有效,就是看看web服務器證書是否在有效期,是否被吊銷了。二、對方是否是上述證書的合法持有者。簡單來講證實對方是否持有證書的對應私鑰。驗證方法兩種,一種是對方籤個名,我用證書驗證簽名;另一種是用證書作個信封,看對方是否能解開。以上的全部驗證,除了驗證證書是否吊銷須要和CA關聯,其餘均可以本身完成。驗證正式是否吊銷能夠採用黑名單方式或者OCSP方式。黑名單就是按期從CA下載一個名單列表,裏面有吊銷的證書序列號,本身在本地比對一下就行。優勢是效率高。缺點是不實時。OCSP是實時鏈接CA去驗證,優勢是實時,缺點是效率不高。
client如何肯定本身發送的消息被server收到?
HTTP協議裏,有請求就有響應,根據響應的狀態嗎就能知道。
HttpClient與HttpUrlConnection的區別 (此處延伸:Volley裏用的哪一種請求方式(2.3前HttpClient,2.3後HttpUrlConnection)
首先HttpClient和HttpUrlConnection 這兩種方式都支持Https協議,都是以流的形式進行上傳或者下載數據,也能夠說是以流的形式進行數據的傳輸,還有ipv6,以及鏈接池等功能。HttpClient這個擁有很是多的API,因此若是想要進行擴展的話,而且不破壞它的兼容性的話,很難進行擴展,也就是這個緣由,Google在Android6.0的時候,直接就棄用了這個HttpClient.
而HttpUrlConnection相對來講就是比較輕量級了,API比較少,容易擴展,而且可以知足Android大部分的數據傳輸。比較經典的一個框架volley,在2.3版本之前都是使用HttpClient,在2.3之後就使用了HttpUrlConnection。
69)、WebSocket與socket的區別
1.WebSocket protocol 是HTML5一種新的協議。它實現了瀏覽器與服務器全雙工通訊(full-duplex)。一開始的握手須要藉助HTTP請求完成。
2.Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把...
3.區別 Socket是傳輸控制層協議,WebSocket是應用層協議。
70)、談談你對安卓簽名的理解。
每一個應用都必須簽名
應用能夠被不一樣的簽名文件簽名(若是有源代碼或者反編譯後從新編譯)
同一個應用若是簽名不一樣則不能覆蓋安裝
71)、請解釋安卓爲啥要加簽名機制?
發送者的身份認證:因爲開發商可能經過使用相同的 Package Name 來混淆替換已經安裝的程序,以此保證簽名不一樣的包不被替換
保證信息傳輸的完整性:簽名對於包中的每一個文件進行處理,以此確保包中內容不被替換
防止交易中的抵賴發生:Market(應用市場)對軟件的要求
72)、視頻加密傳輸
DES加密。用java中提供的加密包。
將視頻文件的數據流前100個字節中的每一個字節與其下標進行異或運算。解密時只需將加密過的文件再進行一次異或運算便可。
73)、App 是如何沙箱化,爲何要這麼作?
在Android系統中,應用(一般)都在一個獨立的沙箱中運行,即每個Android應用程序都在它本身的進程中運行,都擁有一個獨立的Dalvik虛擬機實例。Dalvik通過優化,容許在有限的內存中同時高效地運行多個虛擬機的實例,而且每個Dalvik應用做爲一個獨立的Linux進程執行。Android這種基於Linux的進程「沙箱」機制,是整個安全設計的基礎之一。
Android擴展了Linux內核安全模型的用戶與權限機制,將多用戶操做系統的用戶隔離機制巧妙地移植爲應用程序隔離。將UID(一個用戶標識)不一樣的應用程序天然造成資源隔離,如此便造成了一個操做系統級別的應用程序「沙箱」。
2、Android面試題(基礎+進階)(必須)
1)、四大組件是什麼(這個不知道的話,不必去面試了,轉行吧)
Android四大組件有Activity,Service服務,Content Provider內容提供,BroadcastReceiver。
2)、四大組件的生命週期和簡單用法
activity:onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()
3)、Service:
service 啓動方式有兩種,一種是經過startService()方式進行啓動,另外一種是經過bindService()方式進行啓動。不一樣的啓動方式他們的生命週期是不同.
經過startService()這種方式啓動的service,生命週期是這樣:調用startService() --> onCreate()--> onStartConmon()--> onDestroy()。這種方式啓動的話,須要注意一下幾個問題,第一:當咱們經過startService被調用之後,屢次在調用startService(),onCreate()方法也只會被調用一次,而onStartConmon()會被屢次調用當咱們調用stopService()的時候,onDestroy()就會被調用,從而銷燬服務。第二:當咱們經過startService啓動時候,經過intent傳值,在onStartConmon()方法中獲取值的時候,必定要先判斷intent是否爲null。
經過bindService()方式進行綁定,這種方式綁定service,生命週期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 這種方式進行啓動service好處是更加便利activity中操做service,好比加入service中有幾個方法,a,b ,若是要在activity中調用,在須要在activity獲取ServiceConnection對象,經過ServiceConnection來獲取service中內部類的類對象,而後經過這個類對象就能夠調用類中的方法,固然這個類須要繼承Binder對象
contentProvider:contentProvider的生命週期、理解應該跟進程同樣,它做爲系統應用組件、其生命週期應該跟app應用的生命週期相似,只是它屬於系統應用、因此隨系統啓動而初始化,隨系統關機而結束;但也存在其餘狀態下結束進程、好比說系統內存不夠時,進行內存回收、會根據生成時間態、用戶操做等狀況進行是否內存回收。
BroadcastReceiver:廣播的生命週期從調用開始到onReceiver執行完畢結束,須要注意的是,通常廣播的生命週期都極短,須要在10s內處理完onReceiver中的全部工做,因此,通常不進行耗時長的工做,若是有耗時長的工做,應當經過Intent傳遞給Service進行處理。(注意,不要在onReceiver中開啓線程進行耗時任務處理,不然,在10s後,該線程會變成空線程,從而致使任務的丟失。一樣的,也不要使用bindService來綁定服務。)
值得注意的是,若是是在代碼中動態註冊的廣播,如:在Activity註冊,那麼在Activity的onDestory中須要使用unregisterReceiver註銷廣播。
4)、Activity之間的通訊方式
Intent
藉助類的靜態變量
藉助全局變量/Application
藉助外部工具
藉助SharedPreference
使用Android數據庫SQLite
赤裸裸的使用File
Android剪切板
藉助Service
5)、橫豎屏切換的時候,Activity 各類狀況下的生命週期
分兩種狀況:
1.不設置Activity的android:configChanges,或設置Activity的android:configChanges="orientation",或設置Activity的android:configChanges="orientation|keyboardHidden",切屏會從新調用各個生命週期,切橫屏時會執行一次,切豎屏時會執行一次。
橫豎屏切換形成 activity 的生命週期
onPause()-onSaveInstanceState()-onStop()-onDestroy()-onCreat()-onStart()-onRestoreInstanceState()-onResume()即會致使 activity 的銷燬和重建 。
2.配置 android:configChanges="orientation|keyboardHidden|screenSize",纔不會銷燬 activity,且只調用 onConfigurationChanged方法。
onSaveInstanceState() 與onRestoreIntanceState() 資源相關的系統配置發生改變或者資源不足時(例如屏幕旋轉),當前 Activity 會銷燬,而且在 onStop 以前回調 onSaveInstanceState 保存數據,在從新建立 Activity 的時候在onStart 以後回調 onRestoreInstanceState。其中 Bundle 數據會傳到 onCreate(不必定有數據)和 onRestoreInstanceState(必定有數據)。
用戶或者程序員主動去銷燬一個 Activity 的時候不會回調(如代碼中 finish()或用戶按下 back,不會回調),其餘狀況都會調用,來保存界面信息。
6)、Activity與Fragment之間生命週期比較
a. 在建立的過程當中,是 Activity 帶領 Fragment 執行生命週期的方法,因此它們生命週期執行的順序以下:
Activity -- onCreate() ,
Fragment -- onAttach() -> onCreate() -> onCreateView() -> onActivityCreated
.
Activity -- onStart()
Fragment -- onStart()
Activity -- onResume()
Fragment -- onResume()
最後,在銷燬時是 Fragment 帶領 Activity 執行生命週期的方法:
Fragment -- onPause()
Activity -- onPause()
Fragment -- onStop()
Activity -- onStop()
Fragment -- onDestroyView() -> onDestroy() -> onDetach()
Activity -- onDestroy()
Activity上有Dialog的時候按Home鍵時的生命週期
有 Dialog 和 無 Dialog 按 Home 鍵效果同樣:
7)、兩個Activity 之間跳轉時必然會執行的是哪幾個方法?
a. 正常狀況下 Activity A 跳轉到 Activity B 時:
A調用 onCreate() 方法 -> onStart() 方法 -> onResume() 方法,此時 A 前臺可見。當 A 跳轉到 B 時,A 調用 onPause() 方法,而後調用新的 Activity B 中的 onCreate() 方法 -> onStart() 方法 -> onResume() 方法。最後 A 再調用onStop()方法。
b. 當 Activity B 爲透明主題時:
除了最後 Activity A 不調用 onStop() 方法以外,其它都和 a 中的同樣。
8)、Activity的四種啓動模式對比
此處延伸:棧(First In Last Out)與隊列(First In First Out)的區別
區別:隊列先進先出,棧先進後出
對插入和刪除操做的"限定"。 棧是限定只能在表的一端進行插入和刪除操做的線性表。 隊列是限定只能在表的一端進行插入和在另外一端進行刪除操做的線性表。
遍歷數據速度不一樣
9)、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。
10)、Activity狀態保存於恢復
當 Activity 在異常狀況( 系統內存不足或者系統配置發生了改變等 )被銷燬重建後, 在銷燬的時候 Activity 會調用 onSaveInstanceState() 方法用於保存 Activity 相關的狀態和數據,而後在重建後的 Activity 的中咱們能夠經過 onCreate() 或者 onRestoreInstanceState() 方法恢復數據,這裏咱們須要注意的是若是經過 onCreate() 方法恢復,那麼得先判斷它的 intent 參數 是否爲空,若是在 onRestoreInstanceState() 方法恢復就不會,由於只要 onRestoreInstanceState() 方法被調用就說明必定有數據,不會爲空。Google 推薦使用 onRestoreInstanceState() 方法。
11)、如何實現Fragment的滑動?
將Fragment與viewpager綁定,經過viewpager中的touch事件,會進行move事件的滑動處理。
12)、fragment之間傳遞數據的方式?
一、在fragment中設置一個方法,而後進行調用
二、採起接口回調的方式進行數據傳遞。
三、廣播或者是使用三方開源框架:EventBus
13)、Activity 怎麼和Service 綁定?怎麼在Activity 中啓動本身對應的Service?
一、activity能進行綁定得益於Serviece的接口。爲了支持Service的綁定,實現onBind方法。
二、Service和Activity的鏈接能夠用ServiceConnection來實現。須要實現一個新的ServiceConnection,重現onServiceConnected和OnServiceDisconnected方法,一旦鏈接創建,就能獲得Service實例的引用。
三、執行綁定,調用bindService方法,傳入一個選擇了要綁定的Service的Intent(顯示或隱式)和一個你實現了的ServiceConnection的實例
14)、service和activity怎麼進行數據交互?
1.經過 broadcast:經過廣播發送消息到 activitry
2.經過 Binder:經過與 activity 進行綁定
(1)添加一個繼承 Binder 的內部類,並添加相應的邏輯方法。
(2)重寫 Service 的 onBind 方法,返回咱們剛剛定義的那個內部類實例。
(3)Activity 中建立一個 ServiceConnection 的匿名內部類,而且 重 寫 裏 面 的 onServiceConnected 方 法 和onServiceDisconnected 方法,這兩個方法分別會在活動與服務成功綁定以及解除綁定的時候調用(在onServiceConnected方法中,咱們能夠獲得一個剛纔那個 service 的 binder 對象,經過對這個 binder 對象進行向下轉型,獲得咱們那個自定義的 Binder 實例,有了這個實例,作能夠調用這個實例裏面的具體方法進行須要的操做了)。
15)、Service的開啓方式,請描述一下Service 的生命週期,請描述一下Service 的生命週期
service 啓動方式有兩種,一種是經過startService()方式進行啓動,另外一種是經過bindService()方式進行啓動。不一樣的啓動方式他們的生命週期是不同.
經過startService()這種方式啓動的service,生命週期是這樣:調用startService() --> onCreate()--> onStartConmon()--> onDestroy()。這種方式啓動的話,須要注意一下幾個問題,第一:當咱們經過startService被調用之後,屢次在調用startService(),onCreate()方法也只會被調用一次,而onStartConmon()會被屢次調用當咱們調用stopService()的時候,onDestroy()就會被調用,從而銷燬服務。第二:當咱們經過startService啓動時候,經過intent傳值,在onStartConmon()方法中獲取值的時候,必定要先判斷intent是否爲null。
經過bindService()方式進行綁定,這種方式綁定service,生命週期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 這種方式進行啓動service好處是更加便利activity中操做service,好比加入service中有幾個方法,a,b ,若是要在activity中調用,在須要在activity獲取ServiceConnection對象,經過ServiceConnection來獲取service中內部類的類對象,而後經過這個類對象就能夠調用類中的方法,固然這個類須要繼承Binder對象
16)、請描述一下廣播BroadcastReceiver的理解
廣播,是一個全局的監聽器,屬於Android四大組件之一。Android 廣播分爲兩個角色:廣播發送者、廣播接收者。做用是監聽 / 接收 應用 App 發出的廣播消息,並 作出響應
可應用在:
Android不一樣組件間的通訊(含 :應用內 / 不一樣應用之間)
多線程通訊
與 Android 系統在特定狀況下的通訊
如:電話呼入時、網絡可用時
17)、Broadcast註冊方式與區別 (此處延伸:什麼狀況下用動態註冊)
Broadcast廣播,註冊方式主要有兩種.
第一種是靜態註冊,也可成爲常駐型廣播,這種廣播須要在Androidmanifest.xml中進行註冊,這中方式註冊的廣播,不受頁面生命週期的影響,即便退出了頁面,也能夠收到廣播這種廣播通常用於想開機自啓動啊等等,因爲這種註冊的方式的廣播是常駐型廣播,因此會佔用CPU的資源。
第二種是動態註冊,而動態註冊的話,是在代碼中註冊的,這種註冊方式也叫很是駐型廣播,收到生命週期的影響,退出頁面後,就不會收到廣播,咱們一般運用在更新UI方面。這種註冊方式優先級較高。最後須要解綁,否會會內存泄露
廣播是分爲有序廣播和無序廣播。
在manifest 和代碼中如何註冊和使用BroadcastReceiver?
18)、本地廣播和全局廣播有什麼差異?
BroadcastReceiver是針對應用間、應用與系統間、應用內部進行通訊的一種方式
LocalBroadcastReceiver僅在本身的應用內發送接收廣播,也就是隻有本身的應用能收到,數據更加安全廣播只在這個程序裏,並且效率更高。
19)、BroadcastReceiver,LocalBroadcastReceiver 區別
1、應用場景不一樣
一、BroadcastReceiver用於應用之間的傳遞消息;
二、而LocalBroadcastManager用於應用內部傳遞消息,比broadcastReceiver更加高效。
2、使用安全性不一樣
一、BroadcastReceiver使用的Content API,因此本質上它是跨應用的,因此在使用它時必需要考慮到不要被別的應用濫用;
二、LocalBroadcastManager不須要考慮安全問題,由於它只在應用內部有效。
20)、AlertDialog,popupWindow區別
(1)Popupwindow在顯示以前必定要設置寬高,Dialog無此限制。
(2)Popupwindow默認不會響應物理鍵盤的back,除非顯示設置了popup.setFocusable(true);而在點擊back的時候,Dialog會消失。
(3)Popupwindow不會給頁面其餘的部分添加蒙層,而Dialog會。
(4)Popupwindow沒有標題,Dialog默認有標題,能夠經過dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);取消標題
(5)兩者顯示的時候都要設置Gravity。若是不設置,Dialog默認是Gravity.CENTER。
(6)兩者都有默認的背景,均可以經過setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));去掉。
最本質的區別:AlertDialog是非阻塞式對話框:AlertDialog彈出時,後臺還能夠作事情;而PopupWindow是阻塞式對話框:PopupWindow彈出時,程序會等待,在PopupWindow退出前,程序一直等待,只有當咱們調用了dismiss方法的後,PopupWindow退出,程序纔會向下執行。
21)、講解一下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)
22)、Android屬性動畫特性
(1) 對任意對象的屬性執行動畫操做:屬性動畫容許對任意對象的屬性執行動畫操做,由於屬性動畫的性質是經過反射實現的。
(2)可改變背景顏色。
(3)真正改變 View 自己:由於是經過反射改變其屬性,並刷新,如改變width,他會搜索getWidth(),反射獲取,再經過進行某種計算,將值經過setWidth()設置進去並更新。
23)、LinearLayout、RelativeLayout、FrameLayout的特性及對比,並介紹使用場景。
RelativeLayout的onMeasure過程
根據源碼咱們發現RelativeLayout會根據2次排列的結果對子View各作一次measure。
首先RelativeLayout中子View的排列方式是基於彼此的依賴關係,在肯定每一個子View的位置的時候,須要先給全部的子View排序一下,因此須要橫向縱向分別進行一次排序測量
LinearLayout的onMeasure過程
LinearLayout會先作一個簡單橫縱方向判斷
須要注意的是在每次對child測量完畢後,都會調用child.getMeasuredHeight()/getMeasuredWidth()獲取該子視圖最終的高度,並將這個高度添加到mTotalLength中。
可是getMeasuredHeight暫時避開了lp.weight>0且高度爲0子View,由於後面會將把剩餘高度按weight分配給相應的子View。所以能夠得出如下結論:
(1)若是咱們在LinearLayout中不使用weight屬性,將只進行一次measure的過程。(若是使用weight屬性,則遍歷一次wiew測量後,再遍歷一次view測量)
(2)若是使用了weight屬性,LinearLayout在第一次測量時獲取全部子View的高度,以後再將剩餘高度根據weight加到weight>0的子View上。因而可知,weight屬性對性能是有影響的。
1)RelativeLayout慢於LinearLayout是由於它會讓子View調用2次measure過程,而LinearLayout只需一次,可是有weight屬性存在時,LinearLayout也須要兩次measure。
2)在不響應層級深度的狀況下,使用Linearlayout而不是RelativeLayout。
24)、談談對接口與回調的理解
接口回調就是指: 能夠把使用某一接口的類建立的對象的引用賦給該接口聲明的接口變量,那麼該接口變量就能夠調用被類實現的接口的方法。實際上,當接口變量調用被類實現的接口中的方法時,就是通知相應的對象調用接口的方法,這一過程稱爲對象功能的接口回調。
25)、Android中View,SurfaceView和GLSurfaceView
View:顯示視圖,內置畫布,提供圖形繪製函數,觸屏事件,按鍵事件函數;必須在UI線程中更新畫面,速度較慢。
SurfaceView:基於View視圖進行拓展的視圖類,更適合2D遊戲的開發;是View的子類,相似雙緩機制,在新的線程中更新畫面,因此刷新界面速度比View快。(雙緩機制:即前臺緩存和後臺緩存,後臺緩存計算場景、產生畫面,前臺緩存顯示後臺緩存已畫好的畫面。)
GLSurfaceView:基於SurfaceView視圖再次進行擴展的視圖類,專用於3D遊戲開發的視圖;是SurfaceView的子類,OpenGL專用。(OpenGL:是一個開放的三維圖形軟件包。)
26)、序列化的做用,以及Android兩種序列化的區別
做用:java序列化主要有2個做用:
對象持久化,對象生存在內存中,想把一個對象持久化到磁盤,必須已某種方式來組織這個對象包含的信息,這種方式就是序列化;
遠程網絡通訊,內存中的對象不能直接進行網絡傳輸,發送端把對象序列化成網絡可傳輸的字節流,接收端再把字節流還原成對象。
Serializable Java 序列化接口 在硬盤上讀寫 讀寫過程當中有大量臨時變量的生成,內部執行大量的i/o操做,效率很低。
Parcelable Android 序列化接口 效率高 使用麻煩 在內存中讀寫(AS有相關插件 一鍵生成所需方法) ,對象不能保存到磁盤中
27)、差值器和估值器
差值器: 根據時間流逝的百分比計算當前屬性改變的百分比。
估值器: 根據當前屬性改變的百分比計算改變後的屬性值
28)、Android中數據存儲方式
1 使用SharedPreferences存儲數據
適用範圍:保存少許的數據,且這些數據的格式很是簡單:字符串型、基本類型的值。
好比應用程序的各類配置信息(如是否打開音效等),解鎖口 令密碼等
核心原理:保存基於XML文件存儲的key-value鍵值對數據,一般用來存儲一些簡單的配置信息。
2 文件存儲數據
核心原理: Context提供了兩個方法來打開數據文件裏的文件IO流:
FileInputStream openFileInput(String name);
FileOutputStream openFileOutput(String name , int mode)
3 SQLite數據庫存儲數據
4 使用ContentProvider存儲數據
5 網絡存儲數據
29)、Requestlayout,onlayout,onDraw,DrawChild區別與聯繫
requestLayout()方法 :會致使調用measure()過程 和 layout()過程 。 說明:只是對View樹從新佈局layout過程包括measure()和layout()過程,不會調用draw()過程,但不會從新繪製 任何視圖包括該調用者自己。
onLayout()方法(若是該View是ViewGroup對象,須要實現該方法,對每一個子視圖進行佈局)
調用onDraw()方法繪製視圖自己 (每一個View都須要重載該方法,ViewGroup不須要實現該方法)
drawChild()去從新回調每一個子視圖的draw()方法
30)、invalidate和postInvalidate的區別及使用
一、postInvalidate() 方法在非 UI 線程中調用,通知 UI 線程重繪。
二、invalidate()方法在 UI 線程中調用,重繪當前 UI。Invalidate不能直接在線程中調用,由於他是違背了單線程模型:Android UI操做並非線程安全的,而且這些操做必須在UI線程中調用。
31)、Activity-Window-View三者的差異
這個問題真的很很差回答。因此這裏先來個算是比較恰當的比喻來形容下它們的關係吧。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等。
32)、ActivityThread,AMS,WMS的工做原理
Activity與Window:
Activity只負責生命週期和事件處理
Window只控制視圖
一個Activity包含一個Window,若是Activity沒有Window,那就至關於Service。
33)、AMS與WMS:
AMS統一調度全部應用程序的Activity
WMS控制全部Window的顯示與隱藏以及要顯示的位置。在視圖層次中,Activity在WIndow之上
ActivityThread:是Android應用的主線程(UI線程)
WMS(WindowManagerService):管理的整個系統全部窗口的UI
做用:
爲全部窗口分配Surface:客戶端向WMS添加一個窗口的過程,其實就是WMS爲其分配一塊Suiface的過程,一塊塊Surface在WMS的管理下有序的排布在屏幕上。Window的本質就是Surface。(簡單的說Surface對應了一塊屏幕緩衝區)
管理Surface的顯示順序、尺寸、位置
管理窗口動畫
輸入系統相關:WMS是派發系統按鍵和觸摸消息的最佳人選,當接收到一個觸摸事件,它須要尋找一個最合適的窗口來處理消息,而WMS是窗口的管理者,系統中全部的窗口狀態和信息都在其掌握之中,完成這一工做不在話下。
AMS(ActivityManagerService)
ActivityManager是客戶端用來管理系統中正在運行的全部Activity包括Task、Memory、Service等信息的工具。可是這些這些信息的維護工做卻不是又ActivityManager負責的。在ActivityManager中有大量的get()方法,那麼也就說明了他只是提供信息給AMS,由AMS去完成交互和調度工做。
做用:
統一調度全部應用程序的Activity的生命週期
啓動或殺死應用程序的進程
啓動並調度Service的生命週期
註冊BroadcastReceiver,並接收和分發Broadcast
啓動併發布ContentProvider
調度task
處理應用程序的Crash
查詢系統當前運行狀態
34)、自定義View如何考慮機型適配
佈局類建議:
合理使用warp_content,match_parent.
儘量的是使用RelativeLayout
引入android的百分比佈局。
針對不一樣的機型,使用不一樣的佈局文
件放在對應的目錄下,android會自動匹配。
35)、Icon類建議:
儘可能使用svg轉換而成xml。
切圖的時候切大分辨率的圖,應用到佈局當中。在小分辨率的手機上也會有很好的顯示效果。
使用與密度無關的像素單位dp,sp
36)、AsyncTask 如何使用?
Android的AsyncTask比Handler更輕量級一些,適用於簡單的異步處理。
首先明確Android之因此有Handler和AsyncTask,都是爲了避免阻塞主線程(UI線程),且UI的更新只能在主線程中完成,所以異步處理是不可避免的。
Android爲了下降這個開發難度,提供了AsyncTask。AsyncTask就是一個封裝過的後臺任務類,顧名思義就是異步任務。
AsyncTask直接繼承於Object類,位置爲android.os.AsyncTask。要使用AsyncTask工做咱們要提供三個泛型參數,並重載幾個方法(至少重載一個)。
例:
public class Task extends AsyncTask<void,void,void>//Void是三個泛型參數的原始狀態,而且Void也是一個類而不是void
AsyncTask定義了三種泛型類型 Params,Progress和Result。
Params 啓動任務執行的輸入參數,好比HTTP請求的URL。(可傳入多個參數)
Progress 後臺任務執行的百分比。
Result 後臺執行任務最終返回的結果,好比String。
使用過AsyncTask 的同窗都知道一個異步加載數據最少要重寫如下這兩個方法:
doInBackground(Params…) 後臺執行,比較耗時的操做均可以放在這裏。注意這裏不能直接操做UI。此方法在後臺線程執行,完成任務的主要工做,一般須要較長的時間。在執行過程當中能夠調用publicProgress(Progress…)來更新任務的進度。
publicProgress(Progress…)會將Progress...傳給onProgressUpdate(Progress...)做爲ProgressUpdate(Progress...)的接收參數。
onPostExecute(Result) 至關於Handler 處理UI的方式,在這裏面能夠使用在doInBackground 獲得的結果處理操做UI。 此方法在主線程執行,任務執行的結果做爲此方法的參數返回
有必要的話你還得重寫如下這三個方法,但不是必須的:
onProgressUpdate(Progress…) 能夠使用進度條增長用戶體驗度。 此方法在主線程執行,用於顯示任務執行的進度。
onPreExecute() 這裏是最終用戶調用Excute時的接口,當任務執行以前開始調用此方法,能夠在這裏顯示進度對話框。
onCancelled() 用戶調用取消時,要作的操做
使用AsyncTask類,如下是幾條必須遵照的準則:
Task的實例必須在UI thread(主線程)中建立;
execute方法必須在UI thread中調用;
不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)這幾個方法;
該task只能被執行一次,不然屢次調用時將會出現異常;
37)、SpareArray與HashMap比較,應用場景
SparseArray採用的不是哈希算法,HashMap採用的是哈希算法。
SparseArray採用的是兩個一維數組分別用於存儲鍵和值,HashMap採用的是一維數組+單向鏈表或二叉樹。
SparseArray key只能是int類型,而HashMap的key是Object。
SparseArray key是有序存儲(升序),而HashMap不是。
SparseArray 默認容量是10,而HashMap默認容量是16。
SparseArray 默認每次擴容是2倍於原來的容量,而HashMap默認每次擴容時是原容量*0.75倍
SparseArray value的存儲被不像HashMap同樣須要額外的須要一個實體類(Node)進行包裝
SparseArray查找元素整體而言比HashMap要遜色,由於SparseArray查找是須要通過二分法的過程,而HashMap不存在衝突的狀況其技術處的hash對應的下標直接就能夠取到值。
針對上面與HashMap的比較,採用SparseArray仍是HashMap,建議根據以下需求選取:
若是對內存要求比較高,而對查詢效率沒什麼大的要求,能夠是使用SparseArray
數量在百級別的SparseArray比HashMap有更好的優點
要求key是int類型的,由於HashMap會對int自定裝箱變成Integer類型
要求key是有序的且是升序
38)、請介紹下ContentProvider 是如何實現數據共享的?
一個程序能夠經過實現一個Content provider的抽象接口將本身的數據徹底暴露出去,並且Content providers是以相似數據庫中表的方式將數據暴露。Content providers存儲和檢索數據,經過它可讓全部的應用程序訪問到,這也是應用程序之間惟一共享數據的方法。
要想使應用程序的數據公開化,可經過2種方法:建立一個屬於你本身的Content provider或者將你的數據添加到一個已經存在的Content provider中,前提是有相同數據類型而且有寫入Content provider的權限。
如何經過一套標準及統一的接口獲取其餘應用程序暴露的數據?
Android提供了ContentResolver,外界的程序能夠經過ContentResolver接口訪問ContentProvider提供的數據。
39)、AndroidService與Activity之間通訊的幾種方式
經過 broadcast:經過廣播發送消息到 activitry
經過 Binder:經過與 activity 進行綁定
40)、IntentService原理及做用是什麼?
IntentService是繼承於Service並處理異步請求的一個類,在IntentService內有一個工做線程來處理耗時操做,啓動IntentService的方式和啓動傳統Service同樣,同時,當任務執行完後,IntentService會自動中止,而不須要咱們去手動控制。另外,能夠啓動IntentService屢次,而每個耗時操做會以工做隊列的方式在IntentService的onHandleIntent回調方法中執行,而且,每次只會執行一個工做線程,執行完第一個再執行第二個,以此類推。
全部請求都在一個單線程中,不會阻塞應用程序的主線程(UI Thread),同一時間只處理一個請求。
41)、說說Activity、Intent、Service 是什麼關係
一個 Activity 一般是一個單獨的屏幕,每個 Activity 都被實現爲一個單獨的類,這些類都 是從 Activity 基類中繼承來的, Activity 類會顯示由視圖控件組成的用戶接口,並對視圖控 件的事件作出響應。
Intent 的調用是用來進行架構屏幕之間的切換的。 Intent 是描述應用想要作什麼。 Intent 數 據結構中兩個最重要的部分是動做和動做 對應的數據, 一個動做對應一個動做數據。
Android Service 是運行在後臺的代碼,不能與用戶交互,能夠運行在本身的進程,也能夠 運行在其餘應用程序進程的上下文裏。須要經過某一個 Activity 或者其餘 Context 對象來調 用。 Activity 跳轉到 Activity,Activity 啓動 Service,Service 打開 Activity ,Activity 跳轉到 Activity,Activity 啓動 Service,Service 打開 Activity
SP是進程同步的嗎?有什麼方法作到同步?
SharedPreferences不支持進程同步
一個進程的狀況,常常採用SharePreference來作,可是SharePreference不支持多進程,它基於單個文件的,默認是沒有考慮同步互斥,並且,APP對SP對象作了緩存,很差互斥同步。
考慮用ContentProvider來實現SharedPreferences的進程同步,ContentProvider基於Binder,不存在進程間互斥問題,對於同步,也作了很好的封裝,不須要開發者額外實現。另外ContentProvider的每次操做都會從新getSP,保證了sp的一致性。
42)、談談多線程在Android中的使用
Handler+Thread
AsyncTask
ThreadPoolExecutor
IntentService
43)、進程和 Application 的生命週期
onCreate():Application建立的時候調用
onConfigurationChanged(Configuration newConfig):當配置信息改變的時候會調用,如屏幕旋轉、語言切換時。
onLowMemory():Android系統總體內存較低時候調用,一般在這裏釋放一些不重要的資源,或者提醒用戶清一下垃圾,來保證內存足夠而讓APP進程不被系統殺掉。它和OnTrimMemory中的TRIM_MEMORY_COMPLETE級別相同。
onTrimMemory(int level):Android 4.0 以後提供的一個API,用於取代onLowMemory()。在系統內存不足的時會被調用,提示開發者清理部分資源來釋放內存,從而避免被 Android 系統殺死。詳見《Android代碼內存優化建議-OnTrimMemory優化》
onTerminate():Application結束的時候會調用,由系統決定調用的時機
44)、封裝View的時候怎麼知道view的大小
這裏考點是自定義的那幾個方法含義,源碼理解。須要本身去看看源碼,而後用本身的話表達出來。
45)、AndroidManifest的做用與理解
AndroidManifest.xml 是每一個android程序中必須的文件。它位於整個項目的根目錄,描述了package中暴露的組件(activities, services等等),他們各自的實現類,各類能被處理的數據和啓動位置。 除了能聲明程序中的Activities, ContentProviders, Services, 和Intent Receivers,還能指定permissions和instrumentation(安全控制和測試)。
46)、Handler、Thread和HandlerThread的差異
Handler:在Android中負責發送和處理消息,經過它能夠實現其餘支線線程與主線程之間的消通信
Thread:線程,能夠看做是進程的一個實體,是CPU調度和分派的基本單位,他是比進程更小的獨立運行的基本單位
HandlerThread:封裝了Handler + ThreadHandlerThread適合在有須要一個工做線程(非UI線程)+任務的等待隊列的形式,優勢是不會有堵塞,減小了對性能的消耗,缺點是不能同時進行多個任務的處理,須要等待進行處理。處理效率低,能夠當成一個輕量級的線程池來用
47)、爲何在主線程能夠直接使用 Handler?
由於主線程已經建立了 Looper 對象並開啓了消息循環
關於Handler,在任何地方new Handler 都是什麼線程下?
不傳遞 Looper 建立 Handler:Handler handler = new Handler();上文就是 Handler 無參建立的源碼,
能夠看到是經過 Looper.myLooper() 來獲取 Looper 對象,也就是說對於不傳遞 Looper 對象的狀況下,
在哪一個線程建立 Handler 默認獲取的就是該線程的 Looper 對象,那麼 Handler 的一系列操做都是在該
線程進行的。
對於傳遞 Looper 對象建立 Handler 的狀況下,傳遞的 Looper 是哪一個線程的,Handler 綁定的就是該線程。
ThreadLocal原理,實現及如何保證Local屬性?
ThreadLocal:當某些數據是以線程爲做用域而且不一樣線程具備不一樣的數據副本的時候,就能夠考慮採用ThreadLocal。(Looper、ActivityThread以及AMS中都用到了),如使用ThreadLocal能夠解決不一樣線程不一樣Looper的需求。
雖然在不一樣線程中訪問的是同一個ThreadLocal對象,可是它們經過ThreadLocal來獲取到的值倒是不同的,這就是ThreadLocal的奇妙之處。ThreadLocal之因此有這麼奇妙的效果,是由於不一樣線程訪問同一個ThreadLocal的get方法,ThreadLocal內部會從各自的線程中取出一個數組,而後再從數組中根據當前ThreadLocal的索引去查找出對應的value值,很顯然,不一樣線程中的數組是不一樣的,這就是爲何經過ThreadLocal能夠在不一樣的線程中維護一套數據的副本而且彼此互不干擾。(從ThreadLocal的set和get方法能夠看出,它們所操做的對象都是當前線程的localValues對象的table數組,所以在不一樣線程中訪問同一個ThreadLocal的set和get方法,它們對ThreadLocal所作的讀寫操做僅限於各自線程的內部,這就是爲何ThreadLocal能夠在多個線程中互不干擾地存儲和修改數據。)
Handler機制和底層實現
上面一共出現了幾種類,ActivityThread,Handler,MessageQueue,Looper,msg(Message),對這些類做簡要介紹:
ActivityThread:程序的啓動入口,該類就是咱們說的主線程,它對Looper進行操做的。
Handler:字面意思是操控者,該類有比較重要的地方,就是經過handler來發送消息(sendMessage)到
MessageQueue和 操做控件的更新(handleMessage)。handler下面持有這MessageQueue和Looper的對象。
MessageQueue:字面意思是消息隊列,就是封裝Message類。對Message進行插入和取出操做。
Message:這個類是封裝消息體並被髮送到MessageQueue中的,給類是經過鏈表實現的,其好處方便MessageQueue的插入和取出操做。還有一些字段是(int what,Object obj,int arg1,int arg2)。what是用戶定義的消息和代碼,以便接收者(handler)知道這個是關於什麼的。obj是用來傳輸任意對象的,arg1和arg2是用來傳遞一些簡單的整數類型的。
先獲取looper,若是沒有就建立
建立過程:
ActivityThread 執行looperMainPrepare(),該方法先實例化MessageQueue對象,而後實例化Looper對象,封裝mQueue和主線程,把本身放入ThreadLocal中
再執行loop()方法,裏面會重複死循環執行讀取MessageQueue。接着ActivityThread 執行Looper對象中的loop()方法)
此時調用sendMessage()方法,往MessageQueue中添加數據,其取出消息隊列中的handler,執行dispatchMessage(),進而執行handleMessage(),Message的數據結構是基於鏈表的
Looper爲何要無限循環?
主線程中若是沒有looper進行循環,那麼主線程一運行完畢就會退出。那麼咱們還能運行APP嗎,顯然,這是不可能的,Looper主要就是作消息循環,而後由Handler進行消息分發處理,一旦退出消息循環,那麼你的應用也就退出了。
主線程中的Looper.loop()一直無限循環爲何不會形成ANR?
主線程Looper從消息隊列讀取消息,當讀完全部消息時,主線程阻塞。子線程往消息隊列發送消息,而且往管道文件寫數據,主線程即被喚醒,從管道文件讀取數據,主線程被喚醒只是爲了讀取消息,當消息讀取完畢,再次睡眠。所以loop的循環並不會對CPU性能有過多的消耗。
請解釋下在單線程模型中Message、Handler、Message Queue、Looper之間的關係
Android中主線程是不能進行耗時操做的,子線程是不能進行更新UI的。因此就有了handler,它的做用就是實現線程之間的通訊。
handler整個流程中,主要有四個對象,handler,Message,MessageQueue,Looper。當應用建立的時候,就會在主線程中建立handler對象,
咱們經過要傳送的消息保存到Message中,handler經過調用sendMessage方法將Message發送到MessageQueue中,Looper對象就會不斷的調用loop()方法
不斷的從MessageQueue中取出Message交給handler進行處理。從而實現線程之間的通訊。
48)、請描述一下View事件傳遞分發機制
Touch事件分發中只有兩個主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三個相關事件。View包含dispatchTouchEvent、onTouchEvent兩個相關事件。其中ViewGroup又繼承於View。
2.ViewGroup和View組成了一個樹狀結構,根節點爲Activity內部包含的一個ViwGroup。
3.觸摸事件由Action_Down、Action_Move、Aciton_UP組成,其中一次完整的觸摸事件中,Down和Up都只有一個,Move有若干個,能夠爲0個。
4.當Acitivty接收到Touch事件時,將遍歷子View進行Down事件的分發。ViewGroup的遍歷能夠當作是遞歸的。分發的目的是爲了找到真正要處理本次完整觸摸事件的View,這個View會在onTouchuEvent結果返回true。
5.當某個子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。
6.當ViewGroup中全部子View都不捕獲Down事件時,將觸發ViewGroup自身的onTouch事件。觸發的方式是調用super.dispatchTouchEvent函數,即父類View的dispatchTouchEvent方法。在全部子View都不處理的狀況下,觸發Acitivity的onTouchEvent方法。
7.onInterceptTouchEvent有兩個做用:1.攔截Down事件的分發。2.停止Up和Move事件向目標View傳遞,使得目標View所在的ViewGroup捕獲Up和Move事件。
事件分發中的onTouch 和onTouchEvent 有什麼區別,又該如何使用?
OnTouch方法:
onTouch()是OnTouchListener接口的方法,它是獲取某一個控件的觸摸事件,所以使用時。經過getAction()方法能夠獲取當前觸摸事件的狀態:如:ACTION_DOWN:表示按下了屏幕的狀態。
OnTouchEvent()方法:
onTouchEvent是手機屏幕事件的處理方法,是獲取的對屏幕的各類操做,好比向左向右滑動,點擊返回按鈕等等。
經過查看安卓源碼中View對dispatchTouchEvent的實現,能夠知道onTouchListener(onTouch方法在其中)的接口的執行順序是要先於onTouchEvent的,onTouch方法會先觸發。
若是onTouchListener中的onTouch方法返回true,表示這次事件已經被消費了,那onTouchEvent是接收不到消息的。(內置諸如click事件的實現等等都基於onTouchEvent,這些事件將不會被觸發),若是onTouch方法返回false會接着觸發onTouchEvent。
View刷新機制
經過ViewRootImpl的scheduleTraversals()進行界面的三大流程。
調用到scheduleTraversals()時不會當即執行,而是將該操做保存到待執行隊列中。並給底層的刷新信號註冊監聽。當VSYNC信號到來時,會從待執行隊列中取出對應的scheduleTraversals()操做,並將其加入到主線程的消息隊列中。
主線程從消息隊列中取出並執行三大流程: onMeasure()-onLayout()-onDraw()
49)、View繪製流程
自定義控件:
一、組合控件。這種自定義控件不須要咱們本身繪製,而是使用原生控件組合成的新控件。如標題欄。
二、繼承原有的控件。這種自定義控件在原生控件提供的方法外,能夠本身添加一些方法。如製做圓角,圓形圖片。
三、徹底自定義控件:這個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);⑥、繪製滾動條。
50)、自定義View如何提供獲取View屬性的接口?
自定義屬性的實現流程:
1.在values目錄下定義一個attrs.xml :在res/values/attr.xml中定義相關屬性。
2.在對應的類文件裏生成某些組件 :在對應類的構造函數中經過 obtainStyledAttributes()方法得到自定義屬性的相關值
3.在layout佈局文件裏爲這些屬性賦值:在佈局中添加爲該自定義組件設置一個命名空間,而且相關屬性賦值
51)、AsyncTask是什麼?
AsyncTask使得能夠恰當和簡單地使用 UI線程。這個class容許你在後臺作一些事情,而後把進度和結果告訴UI線程,而不須要操做handler和線程。
52)、AsyncTask設計的思想是什麼?
AsyncTask的設計是爲了成爲一個關於Thread和Handler的幫助類,並非一個通用的線程框架。AsyncTask理想狀況下,應該被使用於很是短的操做(最多幾秒)。若是您但願您的線程能夠運行很長時間,很是建議您使用java.util.concurrent包裏面的API。例如Executor,ThreadPoolExecutor 和FutureTask
AsyncTask原理及不足
原理:
AsyncTask是Android自己提供的一種輕量級的異步任務類。它能夠在線程池中執行後臺任務,而後把執行的進度和最終的結果傳遞給主線程更新UI。實際上,AsyncTask內部是封裝了Thread和Handler。雖然AsyncTask很方便的執行後臺任務,以及在主線程上更新UI,可是,AsyncTask並不合適進行特別耗時的後臺操做,對於特別耗時的任務,我的仍是建議使用線程池。
AsyncTask提供有4個核心方法:
一、onPreExecute():該方法在主線程中執行,在執行異步任務以前會被調用,通常用於一些準備工做。
二、doInBackground(String... params):這個方法是在線程池中執行,此方法用於執行異步任務。在這個方法中能夠經過publishProgress方法來更新任務的進度,publishProgress方法會調用onProgressUpdate方法,另外,任務的結果返回給onPostExecute方法。
三、onProgressUpdate(Object... values):該方法在主線程中執行,主要用於任務進度更新的時候,該方法會被調用。
四、onPostExecute(Long aLong):在主線程中執行,在異步任務執行完畢以後,該方法會被調用,該方法的參數及爲後臺的返回結果。
除了這幾個方法以外還有一些不太經常使用的方法,如onCancelled(),在異步任務取消的狀況下,該方法會被調用。
源碼能夠知道從上面的execute方法內部調用的是executeOnExecutor()方法,即executeOnExecutor(sDefaultExecutor, params);而sDefaultExecutor其實是一個串行的線程池。而onPreExecute()方法在這裏就會被調用了。接着看這個線程池。AsyncTask的執行是排隊執行的,由於有關鍵字synchronized,而AsyncTask的Params參數就封裝成爲FutureTask類,FutureTask這個類是一個併發類,在這裏它充當了Runnable的做用。接着FutureTask會交給SerialExecutor的execute方法去處理,而SerialExecutor的executor方法首先就會將FutureTask添加到mTasks隊列中,若是這個時候沒有任務,就會調用scheduleNext()方法,執行下一個任務。若是有任務的話,則執行完畢後最後在調用 scheduleNext();執行下一個任務。直到全部任務被執行完畢。而AsyncTask的構造方法中有一個call()方法,而這個方法因爲會被FutureTask的run方法執行。因此最終這個call方法會在線程池中執行。而doInBackground這個方法就是在這裏被調用的。咱們好好研究一下這個call()方法。mTaskInvoked.set(true);表示當前任務已經執行過了。接着執行doInBackground方法,最後將結果經過postResult(result);方法進行傳遞。postResult()方法中經過sHandler來發送消息,sHandler的中經過消息的類型來判斷一個MESSAGE_POST_RESULT,這種狀況就是調用onPostExecute(result)方法或者是onCancelled(result)。另外一種消息類型是MESSAGE_POST_PROGRESS則調用更新進度onProgressUpdate。
不足:AsyncTask的優勢在於執行完後臺任務後能夠很方便的更新UI,然而使用它存在着諸多的限制。先拋開內存泄漏問題,使用AsyncTask主要存在如下侷限性:
在Android 4.1版本以前,AsyncTask類必須在主線程中加載,這意味着對AsyncTask類的第一次訪問必須發生在主線程中;在Android 4.1以及以上版本則不存在這一限制,由於ActivityThread(表明了主線程)的main方法中會自動加載AsyncTask
AsyncTask對象必須在主線程中建立
AsyncTask對象的execute方法必須在主線程中調用
一個AsyncTask對象只能調用一次execute方法
53)、如何取消AsyncTask?
1.調用cancel():可是他是在在doInBackground()以後執行
若是調用cancel()方法,它不會當即執行,只有當doInBackground()方法執行完有返回值以後,會在UI主線程調用cancel(),同時也會間接的調用iscancelled(),而且返回true ,這個時候就不會再調onPostExecute(),而後在doInBackground()裏按期檢查iscancelled()方法的返回值,是否被cancel,若是return true,就儘快中止。
2.在耗時操做中設置一些flag:咱們能夠在這個線程中的耗時操做中設置一些flag,也就是AsyncTask的doInBackground方法中的某些關鍵步驟。
而後在外層須要終止此線程的地方改變這個flag值,線程中的耗時代碼一步步執行,當某一時刻發現flag的值變了,throwException,線程就不會再繼續執行了。爲了保險起見,在外層咱們還要捕獲這個異常,進行相應處理。(子線程被髮生異常後會本身死掉而不會引發其餘問題,更不會影響到主線程,更況且咱們爲了更加安全還捕獲了異常並作處理)
54)、AsyncTask適合作什麼?
必須同時知足如下條件:
a.執行過程單一,僅輸入一次,輸出一次。
b.花費時間很是短可是仍然須要到後臺去作事情,而後更新UI。例如加載文件,web頁面或者數據庫到UI。
c.執行線程必須是UI線程
d.不須要長期維護狀態。
55)、AsyncTask不適合作什麼?
a.長時間的任務。
b.可重複調用的任務。
c.須要線程執行多個不一樣任務,任務之間又有關聯。
d.執行線程不是UI線程。
e.任務執行後仍然須要維護一些狀態。
f.後臺服務模塊,須要提供獨立的API.
56)、爲何不能在子線程更新UI?
目的在於提升移動端更新UI的效率和和安全性,以此帶來流暢的體驗。緣由是:
Android的UI訪問是沒有加鎖的,多個線程能夠同時訪問更新操做同一個UI控件。也就是說訪問UI的時候,android系統當中的控件都不是線程安全的,這將致使在多線程模式下,當多個線程共同訪問更新操做同一個UI控件時容易發生不可控的錯誤,而這是致命的。因此Android中規定只能在UI線程中訪問UI,這至關於從另外一個角度給Android的UI訪問加上鎖,一個僞鎖。
57)、ANR產生的緣由是什麼?
ANR即Application Not Responding,顧名思義就是應用程序無響應。
在Android中,通常狀況下,四大組件均是工做在主線程中的,Android中的Activity Manager和Window Manager會隨時監控應用程序的響應狀況,若是由於一些耗時操做(網絡請求或者IO操做)形成主線程阻塞必定時間(例如形成5s內不能響應用戶事件或者BroadcastReceiver的onReceive方法執行時間超過10s),那麼系統就會顯示ANR對話框提示用戶對應的應用處於無響應狀態。
ANR定位和修正
ANR通常有三種類型
KeyDispatchTimeout(5 seconds) –主要類型
按鍵或觸摸事件在特定時間內無響應
BroadcastTimeout(10 seconds)
BroadcastReceiver在特定時間內沒法處理完成
ServiceTimeout(20 seconds) –小几率類型
Service在特定的時間內沒法處理完成
一、主線程當中執行IO/網絡操做,容易阻塞。二、主線程當中執行了耗時的計算。(好比自定義控件中的onDraw()方法)在onDraw()方法裏面建立對象容易致使內存抖動(繪製動做時會大量不間斷調用,產生大量垃圾對象致使GC很頻繁,就形成了內存抖動),內存抖動就容易形成UI出現掉幀、卡頓等問題。三、BroadCastReceiver沒有在10秒內完成處理。四、BroadCastReceiver的onReceived代碼中也要儘可能減小耗時的操做,建議使用IntentService處理。五、Service執行了耗時的操做,由於Service也是在主線程當中執行的,因此耗時操做應該在Service裏面開啓子線程來作。六、使用AsyncTask處理耗時的IO等操做。七、Activity的onCreate和onResume回調中儘可能耗時的操做。