設(shè)計模式面試題
1.請列舉出在 JDK 中幾個常用的設(shè)計模式?
單例模式(Singleton pattern)用于 Runtime,Calendar 和其他的一些類中。工廠模式 (Factory pattern)被用于各種不可變的類如 Boolean,像 Boolean.valueOf,觀察者模式 (Observer pattern)被用于 Swing 和很多的事件監(jiān)聽中。裝飾器設(shè)計模式(Decorator design pattern)被用于多個 Java IO 類中。
2.什么是設(shè)計模式?你是否在你的代碼里面使用過任何設(shè)計模式?
設(shè)計模式是世界上各種各樣程序員用來解決特定設(shè)計問題的嘗試和測試的方法。設(shè)計模式是代碼可用性的延伸
3.Java 中什么叫單例設(shè)計模式?請用 Java 寫出線程安全的單例模式
單例模式重點在于在整個系統(tǒng)上共享一些創(chuàng)建時較耗資源的對象。整個應(yīng)用中只維護(hù)一個特定類實例,它被所有組件共同使用。Java.lang.Runtime 是單例模式的經(jīng)典例子。從 Java 5 開始你可以使用枚舉(enum)來實現(xiàn)線程安全的單例。
4.在 Java 中,什么叫觀察者設(shè)計模式(observer design pattern)?
觀察者模式是基于對象的狀態(tài)變化和觀察者的通訊,以便他們作出相應(yīng)的操作。簡單的例子就是一個天氣系統(tǒng),當(dāng)天氣變化時必須在展示給公眾的視圖中進(jìn)行反映。這個視圖對象是一個主體,而不同的視圖是觀察者。
5.使用工廠模式最主要的好處是什么?在哪里使用?
工廠模式的最大好處是增加了創(chuàng)建對象時的封裝層次。如果你使用工廠來創(chuàng)建對象,之后你可以使用更高級和更高性能的實現(xiàn)來替換原始的產(chǎn)品實現(xiàn)或類,這不需要在調(diào)用層做任何修改。
6.舉一個用 Java 實現(xiàn)的裝飾模式(decorator design pattern)?它是作用于對象層次還是類層次?
裝飾模式增加強(qiáng)了單個對象的能力。Java IO 到處都使用了裝飾模式,典型例子就是Buffered 系列類如 BufferedReader 和 BufferedWriter,它們增強(qiáng)了 Reader 和 Writer 對象,以實現(xiàn)提升性能的 Buffer 層次的讀取和寫入。
7.在 Java 中,為什么不允許從靜態(tài)方法中訪問非靜態(tài)變量?
Java 中不能從靜態(tài)上下文訪問非靜態(tài)數(shù)據(jù)只是因為非靜態(tài)變量是跟具體的對象實例關(guān)聯(lián)的,而靜態(tài)的卻沒有和任何實例關(guān)聯(lián)。
8.設(shè)計一個 ATM 機(jī),請說出你的設(shè)計思路?
比如設(shè)計金融系統(tǒng)來說,必須知道它們應(yīng)該在任何情況下都能夠正常工作。不管是斷電還是其他情況,ATM 應(yīng)該保持正確的狀態(tài)(事務(wù)) , 想想 加鎖(locking)、事務(wù)(transaction)、錯誤條件(error condition)、邊界條件(boundary condition) 等等。盡管你不能想到具體的設(shè)計,但如果你可以指出非功能性需求,提出一些問題,想到關(guān)于邊界條件,這些都會是很好的。
9.在 Java 中,什么時候用重載,什么時候用重寫?
如果你看到一個類的不同實現(xiàn)有著不同的方式來做同一件事,那么就應(yīng)該用重寫(overriding),而重載(overloading)是用不同的輸入做同一件事。在 Java 中,重載的方法簽名不同,而重寫并不是。
10.舉例說明什么情況下會更傾向于使用抽象類而不是接口?
接口和抽象類都遵循”面向接口而不是實現(xiàn)編碼”設(shè)計原則,它可以增加代碼的靈活性,可以適應(yīng)不斷變化的需求。下面有幾個點可以幫助你回答這個問題:
在 Java 中,你只能繼承一個類,但可以實現(xiàn)多個接口。所以一旦你繼承了一個類,你就失去了繼承其他類的機(jī)會了。
接口通常被用來表示附屬描述或行為如:Runnable、Clonable、Serializable 等等,因此當(dāng)你使用抽象類來表示行為時,你的類就不能同時是 Runnable 和 Clonable(注:這里的意思是指如果把 Runnable 等實現(xiàn)為抽象類的情況),因為在 Java 中你不能繼承兩個類,但當(dāng)你使用 接口時,你的類就可以同時擁有多個不同的行為。
在一些對時間要求比較高的應(yīng)用中,傾向于使用抽象類,它會比接口稍快一點。
如果希望把一系列行為都規(guī)范在類繼承層次內(nèi),并且可以更好地在同一個地方進(jìn)行編碼,那么抽象類是一個更好的選擇。有時,接口和抽象類可以一起使用,接口中定義函數(shù),而在抽象類中定義默認(rèn)的實現(xiàn)。
數(shù)據(jù)結(jié)構(gòu)面試題1、常用數(shù)據(jù)結(jié)構(gòu)有哪些?
數(shù)據(jù)結(jié)構(gòu)是指相互之間存在著一種或多種關(guān)系的數(shù)據(jù)元素的集合和該集合中數(shù)據(jù)元素間的關(guān)系組成。常用的數(shù)據(jù)有:數(shù)組、棧、隊列、鏈表、樹、圖、堆、散列表。
1)數(shù)組:在內(nèi)存中連續(xù)存儲多個元素的結(jié)構(gòu)。數(shù)組元素通過下標(biāo)訪問,下標(biāo)從0開始。優(yōu)點:訪問速度快;缺點:數(shù)組大小固定后無法擴(kuò)容,只能存儲一種類型的數(shù)據(jù),添加刪除操作慢。適用場景:適用于需頻繁查找,對存儲空間要求不高,很少添加刪除。
2)棧:一種特殊的線性表,只可以在棧頂操作,先進(jìn)后出,從棧頂放入元素叫入棧,從棧頂取出元素叫出棧。應(yīng)用場景:用于實現(xiàn)遞歸功能,如斐波那契數(shù)列。
3)隊列:一種線性表,在列表一端添加元素,另一端取出,先進(jìn)先出。使用場景:多線程阻塞隊列管理中。
4)鏈表:物理存儲單元上非連續(xù)、非順序的存儲結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過鏈表的指針地址實現(xiàn),每個元素包含兩個結(jié)點,一個是存儲元素的數(shù)據(jù)域,一個是指向下一個結(jié)點地址的指針域。有單鏈表、雙向鏈表、循環(huán)鏈表。優(yōu)點:可以任意加減元素,不需要初始化容量,添加刪除元素只需改變前后兩個元素結(jié)點的指針域即可。缺點:因為含有大量指針域,固占用空間大,查找耗時。適用場景:數(shù)據(jù)量小,需頻繁增加刪除操作。
5)樹:由n個有限節(jié)點組成一種具有層次關(guān)系的集合。二叉樹(每個結(jié)點最多有兩個子樹,結(jié)點的度最大為2,左子樹和右子樹有順序)、紅黑樹(HashMap底層源碼)、B+樹(mysql的數(shù)據(jù)庫索引結(jié)構(gòu))
6)散列表(哈希表):根據(jù)鍵值對來存儲訪問。
7)堆:堆中某個節(jié)點的值總是不大于或不小于其父節(jié)點的值,堆總是一棵完全二叉樹。
8)圖:由結(jié)點的有窮集合V和邊的集合E組成。
2、并發(fā)集合了解哪些?
1)并發(fā)List,包括Vector和CopyOnWriteArrayList是兩個線程安全的List,Vector讀寫操作都用了同步,CopyOnWriteArrayList在寫的時候會復(fù)制一個副本,對副本寫,寫完用副本替換原值,讀時不需要同步。
2)并發(fā)Set,CopyOnWriteArraySet基于CopyOnWriteArrayList來實現(xiàn)的,不允許存在重復(fù)的對象。
3)并發(fā)Map,ConcurrentHashMap,內(nèi)部實現(xiàn)了鎖分離,get操作是無鎖的。
4)并發(fā)Queue,ConcurrentLinkedQueue適用于高并發(fā)場景下的隊列,通過無鎖方式實現(xiàn)。 BlockingQueue阻塞隊列,應(yīng)用場景,生產(chǎn)者-消費者模式,若生產(chǎn)快于消費,生產(chǎn)隊列裝滿時會阻塞,等待消費。
5)并發(fā)Deque, LinkedBlockingDueue沒有進(jìn)行讀寫鎖分離,同一時間只能有一個線程對其操作。
6)并發(fā)鎖重入鎖ReentrantLock,互斥鎖,一次最多只能一個線程拿到鎖。
7)讀寫鎖ReadWriteLock,有讀取和寫入鎖兩種,讀取允許多個讀取線程同時持有,而寫入只能有一個線程持有。
3、列舉java的集合以及集合之間的繼承關(guān)系
略
4、容器類介紹以及之間的區(qū)別
1)Collection接口:集合框架的根接口,它是集合類框架中最具一般性的頂層接口。
2)Map接口:提供了鍵值對的映射關(guān)系的集合,關(guān)鍵字不能有重復(fù)值,每個關(guān)鍵字至多可映射一個值。HashMap(通過散列機(jī)制,用于快速訪問),TreeMap(保持key處于排序狀態(tài),訪問速度不如hashmap), LinkedHashMap(保持元素的插入順序)
3)Set接口:可包含重復(fù)的元素,LinkedHashSet TreeSet(用紅黑樹來存儲元素) HashSet
4)List接口:可通過索引對元素進(jìn)行精準(zhǔn)的插入和查找,實現(xiàn)類有ArrayList LinkedList
5)Queue接口:繼承自Collection接口,LinkedList實現(xiàn)了Queue接口,提供了支持隊列的行為。
6)Iterator接口:為了迭代集合
7)Comparable接口:用于比較
5、List,Set,Map的區(qū)別
Set是一個無序的集合,不能包含重復(fù)的元素;
list是一個有序的集合可以包含重復(fù)的元素,提供了按索引訪問的方式;
map包含了key-value對,map中key必須唯一,value可以重復(fù)。
6、HashMap的實現(xiàn)原理
1)數(shù)據(jù)結(jié)構(gòu)
jdk1.7及以前,HashMap由數(shù)組+鏈表組成,數(shù)組Entry是HashMap的主體,Entry是HashMap中的一個靜態(tài)內(nèi)部類,每一個Entry包含一個key-value鍵值對,鏈表是為解決哈希沖突而存在。
從jdk1.8起,HashMap是由數(shù)組+鏈表/紅黑樹組成,當(dāng)某個bucket位置的鏈表長度達(dá)到閥值8時,這個鏈表就轉(zhuǎn)變成紅黑樹。
2)HashMap是線程不安全的,存儲比較快,能接受null值,HashMap通過put(key, value)來儲存元素,通過get(key)來得到value值,通過hash算法來計算hashcode值,用hashcode標(biāo)識Entry在bucket中存儲的位置。
3)HashMap中為什么要使用加載因子,為什么要進(jìn)行擴(kuò)容
加載因子是指當(dāng)HashMap中存儲的元素/最大空間值的閥值,如果超過這個值,就會進(jìn)行擴(kuò)容。加載因子是為了讓空間得到充分利用,如果加載因子太大,雖對空間利用更充分,但查找效率會降低;如果加載因子太小,表中的數(shù)據(jù)過于稀疏,很多空間還沒用就開始擴(kuò)容,就會對空間造成浪費。
至于為什么要擴(kuò)容,如果不擴(kuò)容,HashMap中數(shù)組處的鏈表會越來越長,這樣查找效率就會大大降低。
6.1 HashMap如何put數(shù)據(jù)(從HashMap源碼角度講解)?
當(dāng)我們使用put(key, value)存儲對象到HashMap中時,具體實現(xiàn)步驟如下:
1)先判斷table數(shù)組是否為空,為空以默認(rèn)大小構(gòu)建table,table默認(rèn)空間大小為16
2)計算key的hash值,并計算hash&(n-1)值得到在數(shù)組中的位置index,如果該位置沒值即table[index]為空,則直接將該鍵值對存放在table[index]處。
3)如果table[index]處不為空,說明發(fā)生了hash沖突,判斷table[index]處結(jié)點是否是TreeNode(紅黑樹結(jié)點)類型數(shù)據(jù),如果是則執(zhí)行putTreeVal方法,按紅黑樹規(guī)則將鍵值對存入;
4)如果table[index]是鏈表形式,遍歷該鏈表上的數(shù)據(jù),將該鍵值對放在table[index]處,并將其指向原index處的鏈表。判斷鏈表上的結(jié)點數(shù)是否大于鏈表最大結(jié)點限制(默認(rèn)為8),如果超過了需執(zhí)行treeifyBin()操作,則要將該鏈表轉(zhuǎn)換成紅黑樹結(jié)構(gòu)。
5)判斷HashMap中數(shù)據(jù)個數(shù)是否超過了(最大容量*裝載因子),如果超過了,還需要對其進(jìn)行擴(kuò)容操作。
6.2 HashMap如何get數(shù)據(jù)?
get(key)方法獲取key的hash值,計算hash&(n-1)得到在鏈表數(shù)組中的位置first=table[hash&(n-1)],先判斷first(即數(shù)組中的那個)的key是否與參數(shù)key相等,不等的話,判斷結(jié)點是否是TreeNode類型,是則調(diào)用getTreeNode(hash, key)從二叉樹中查找結(jié)點,不是TreeNode類型說明還是鏈表型,就遍歷鏈表找到相同的key值返回對應(yīng)的value值即可。
6.3 當(dāng)兩個對象的hashcode相同,即發(fā)生碰撞時,HashMap如何處理
當(dāng)兩個對象的hashcode相同,它們的bucket位置相同,hashMap會用鏈表或是紅黑樹來存儲對象。Entry類里有一個next屬性,作用是指向下一個Entry。第一個鍵值對A進(jìn)來,通過計算其key的hash得到index,記做Entry[index]=A。一會又進(jìn)來一個鍵值對B,通過計算其key的hash也是index,HashMap會將B.next=A, Entry[index]=B.如果又進(jìn)來C,其key的hash也是index,會將C.next=B, Entry[index]=C.這樣bucket為index的地方存放了ABC三個鍵值對,它們能過next屬性鏈在一起。數(shù)組中存儲的是最后插入的元素,其他元素都在后面的鏈表里。
6.4 如果兩個鍵的hashcode相同,如何獲取值對象?
當(dāng)調(diào)用get方法時,hashmap會使用鍵對象的hashcode找到bucket位置,找到bucket位置后,會調(diào)用key.equals()方法去找到鏈表中正確的節(jié)點,最終找到值對象。
6.5 hashMap如何擴(kuò)容
HashMap默認(rèn)負(fù)載因為是0.75,當(dāng)一個map填滿了75%的bucket時,和其他集合類一樣,將會創(chuàng)建原來HashMap大小兩倍的bucket數(shù)組,來重新調(diào)整HashMap的大小,并將原來的對象放入新的bucket數(shù)組中。
在jdk1.7及以前,多線程擴(kuò)容可能出現(xiàn)死循環(huán)。因為在調(diào)整大小過程中,存儲在某個bucket位置中的鏈表元素次序會反過來,而多線程情況下可能某個線程翻轉(zhuǎn)完鏈表,另外一個線程又開始翻轉(zhuǎn),條件競爭發(fā)生了,那么就死循環(huán)了。
而在jdk1.8中,會將原來鏈表結(jié)構(gòu)保存至節(jié)點e中,將原來數(shù)組中的位置設(shè)為null,然后依次遍歷e,根據(jù)hash&n是否為0分成兩條支鏈,保存在新數(shù)組中。如果多線程情況可能會取到null值造成數(shù)據(jù)丟失。
7、ConcurrentHashMap的實現(xiàn)原理
1)jdk1.7及以前:一個ConcurrentHashMap由一個segment數(shù)組和多個HashEntry組成,每一個segment都包含一個HashEntry數(shù)組, Segment繼承ReentrantLock用來充當(dāng)鎖角色,每一個segment包含了對自己的HashEntry的操作,如getput eplace操作,這些操作發(fā)生時,對自己的HashEntry進(jìn)行鎖定。由于每一個segment寫操作只鎖定自己的HashEntry,可以存在多個線程同時寫的情況。
jdk1.8以后:ConcurrentHashMap取消了segments字段,采用transient volatile HashEntry<K, V> table保存數(shù)據(jù),采用table數(shù)組元素作為鎖,實現(xiàn)對每一個數(shù)組數(shù)據(jù)進(jìn)行加鎖,進(jìn)一小減少并發(fā)沖突概率。ConcurrentHashMap是用Node數(shù)組+鏈表+紅黑樹數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)的,并發(fā)制定用synchronized和CAS操作。
2)Segment實現(xiàn)了ReentrantLock重入鎖,當(dāng)執(zhí)行put操作,會進(jìn)行第一次key的hash來定位Segment的位置,若該Segment還沒有初始化,會通過CAS操作進(jìn)行賦值,再進(jìn)行第二次hash操作,找到相應(yīng)的HashEntry位置。
8、ArrayMap和HashMap的對比
1)存儲方式不一樣,HashMap內(nèi)部有一個Node<K,V>[]對象,每個鍵值對都會存儲到這個對象里,當(dāng)用put方法添加鍵值對時,會new一個Node對象,tab[i] = newNode(hash, key, value, next);
ArrayMap存儲則是由兩個數(shù)組來維護(hù),int[] mHashes; Object[] mArray; mHashes數(shù)組中保存的是每一項的HashCode值,mArray存的是鍵值對,每兩個元素代表一個鍵值對,前面保存key,后面保存value。mHashes[index]=hash; mArray[index<<1]=key; mArray[(index<<1)+1]=value;
ArrayMap相對于HashMap,無需為每個鍵值對創(chuàng)建Node對象,且在數(shù)組中連續(xù)存放,更省空間。
2)添加數(shù)據(jù)時擴(kuò)容處理不一樣,進(jìn)行了new操作,重新創(chuàng)建對象,開銷很大;而ArrayMap用的是copy數(shù)據(jù),所有效率相對高些;
3)ArrayMap提供了數(shù)組收縮功能,在clear或remove后,會重新收縮數(shù)組,釋放空間;
4)ArrayMap采用二分法查找,mHashes中的hash值是按照從小到大的順序連續(xù)存放的,通過二分查找來獲取對應(yīng)hash下標(biāo)index,去mArray中查找鍵值對。mHashes中的index2是mArray中的key下標(biāo),index2+1為value的下標(biāo),由于存在hash碰撞情況,二分查找到的下標(biāo)可能是多個連續(xù)相同的hash值中的任意一個,此時需要用equals比對命中的key對象是否相等,不相等,應(yīng)當(dāng)從當(dāng)前index先向后再向前遍歷所有相同hash值。
5)sparseArray比ArrayMap進(jìn)一步優(yōu)化空間,SparseArray專門對基本類型做了優(yōu)化,Key只能是可排序的基本類型,如intlong,對value,除了泛型Value,還對每種基本類型有單獨實現(xiàn),如SparseBooleanArraySparseLongArray等。無需包裝,直接使用基本類型值,無需hash,直接使用基本類型值索引和判斷相等,無碰撞,無需調(diào)用hashCode方法,無需equals比較。SparseArray延遲刪除。
9、HashTable實現(xiàn)原理
Hashtable中的無參構(gòu)造方法Hashtable()中調(diào)用了this(11, 0.75f),說明它默認(rèn)容量是11,加載因子是0.75,在構(gòu)造方法上會new HashtableEntry[initialCapacity]; 會新建一個容量是初始容量的HashtableEntry數(shù)組。HashtableEntry數(shù)組中包含hashKeyValue ext變量,鏈表形式,重寫了hashCode和equals方法。Hashtable所有public方法都在方法體上加上了synchronized鎖操作,說明它是線程安全的。它還實現(xiàn)了Serializable接口中的writeObject和readObject方法,分別實現(xiàn)了逐行讀取和寫入的功能,并且加了synchronized鎖操作。
(1) put(Key, Value)方法
1)先判斷value是否為空,為空拋出空指針異常;
2)根據(jù)key的hashCode()值,計算table表中的位置索引(hash&0x7FFFFFFF)%tab.length值index,如果該索引處有值,再判斷該索引處鏈表中是否包含相同的key,如果key值相同則替換舊值。
3)如果沒有相同的key值,調(diào)用addEntry方法,在addEntry中判斷count大小是否超過了最大容量限制,如果超過了需要重新rehash(),容量變成原來容量*2+1,將原表中的值都重新計算hash值放入新表中。再構(gòu)造一個HashtableEntry對象放入相應(yīng)的table表頭,如果原索引處有值,則將table[index].next指向原索引處的鏈表。
(2)get方法
根所key.hashCode(),計算它在table表中的位置,(hash&0x7FFFFFFF)%tab.length,遍歷該索引處表的位置中是否有值,是否存在鏈表,再判斷是key值和hash值是否相等,相等則返回對應(yīng)的value值。
10、HashMap和HashTable的區(qū)別
1)Hashtable是個線程安全的類,在對外方法都添加了synchronized方法,序列化方法上也添加了synchronized同步鎖方法,而HashMap非線程安全。這也導(dǎo)致Hashtable的讀寫等操作比HashMap慢。
2)Hashtable不允許值和鍵為空,若為空會拋出空指針。而HashMap允許鍵和值為空;
3)Hashtable根據(jù)key值的hashCode計算索引,(hash&0x7FFFFFFF)%tab.length,保證hash值始終為正數(shù)且不超過表的長度。而HashMap中計算索引值是通過hash(key)&(tab.length-1),是通過與操作,計算出在表中的位置會比Hashtable快。
4)Hashtable容量能為任意大于等于1的正數(shù),而HashMap的容量必須為2^n,Hashtable默認(rèn)容量為11,HashMap初始容量為16
5)Hashtable每次擴(kuò)容,新容量為舊容量的2倍+1,而HashMap為舊容量的2倍。
11、HashMap與HashSet的區(qū)別 HashSet底層實現(xiàn)是HashMap,內(nèi)部包含一個HashMap<E, Ojbect> map變量
private transient HashMap<E,Object> map; 一個Object PRESENT變量(當(dāng)成插入map中的value值)
private static final Object PRESENT = new Object(); HashSet中元素都存到HashMap鍵值對的Key上面。具體可以查看HashSet的add方法,直接調(diào)用了HashMap的put方法,將值作為HashMap的鍵,值用一個固定的PRESENT值。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
HashSet沒有單獨的get方法,用的是HashMap的。HashSet實現(xiàn)了Set接口,不允許集合中出現(xiàn)重復(fù)元素,將對象存儲進(jìn)HashSet前,要先確保對象重寫了hashCode()和equals方法,以保證放入set對象是唯一的。
12、HashSet與HashMap怎么判斷集合元素重復(fù)?
HashMap在放入key-value鍵值對是,先通過key計算其hashCode()值,再與tab.length-1做與操作,確定下標(biāo)index處是否有值,如果有值,再調(diào)用key對象的equals方法,對象不同則插入到表頭,相同則覆蓋;
HashSet是將數(shù)據(jù)存放到HashMap的key中,HashMap是key-value形式的數(shù)據(jù)結(jié)構(gòu),它的key是唯一的,HashSet利用此原理保證放入的對象唯一性。
13、集合Set實現(xiàn)Hash怎么防止碰撞
HashSet底層實現(xiàn)是HashMap,HashMap如果兩個不同Key對象的hashCode()值相等,會用鏈表存儲,HashSet也一樣。
14、ArrayList和LinkedList的區(qū)別,以及應(yīng)用場景
ArrayList底層是用數(shù)組實現(xiàn)的,隨著元素添加,其大小是動態(tài)增大的;在內(nèi)存中是連續(xù)存放的;如果在集合末尾添加或刪除元素,所用時間是一致的,如果在列表中間添加或刪除元素,所用時間會大大增加。通過索引查找元素速度很快。適合場合:查詢比較多的場景
LinkedList底層是通過雙向鏈表實現(xiàn)的,LinkedList和ArrayList相比,增刪速度快,但查詢和修改值速度慢。在內(nèi)存中不是連續(xù)內(nèi)存。場景:增刪操作比較多的場景。
-二叉樹的深度優(yōu)先遍歷和廣度優(yōu)先遍歷的具體實現(xiàn) -堆的結(jié)構(gòu) -堆和樹的區(qū)別 -堆和棧在內(nèi)存中的區(qū)別是什么(解答提示:可以從數(shù)據(jù)結(jié)構(gòu)方面以及實際實現(xiàn)方面兩個方面去回答)? -什么是深拷貝和淺拷貝 -手寫鏈表逆序代碼 -講一下對樹,B+樹的理解 -講一下對圖的理解 -判斷單鏈表成環(huán)與否? -鏈表翻轉(zhuǎn)(即:翻轉(zhuǎn)一個單項鏈表) -合并多個單有序鏈表(假設(shè)都是遞增的)
Android 基礎(chǔ)與底層機(jī)制面試題最后1.數(shù)據(jù)庫的操作類型有哪些,如何導(dǎo)入外部數(shù)據(jù)庫?
2.是否使用過本地廣播,和全局廣播有什么差別?
3.是否使用過 IntentService,作用是什么, AIDL 解決了什么問題? (小米)
4.Activity、 Window、 View 三者的差別, fragment 的特點?(360)
5.描述一次網(wǎng)絡(luò)請求的流程(新浪)
6.Handler、 Thread 和 HandlerThread 的差別(小米)
7.低版本 SDK 實現(xiàn)高版本 api(小米)
8.launch mode 應(yīng)用場景(百度、小米、樂視)
9.touch 事件傳遞流程(小米)
10.view 繪制流程(百度)
11.什么情況導(dǎo)致內(nèi)存泄漏(美團(tuán))
12.ANR 定位和修正
13.什么情況導(dǎo)致 oom(樂視、美團(tuán))
14.Android Service 與 Activity 之間通信的幾種方式
15.Android 各個版本 API 的區(qū)別
16.如何保證一個后臺服務(wù)不被殺死,比較省電的方式是什么?(百度)
17.Requestlayout, onlayout, onDraw, DrawChild 區(qū)別與聯(lián)系(獵豹)
18.invalidate()和 postInvalidate() 的區(qū)別及使用(百度)
19.Android 動畫框架實現(xiàn)原理(騰訊)
20.Android 為每個應(yīng)用程序分配的內(nèi)存大小是多少?(美團(tuán))
21.LinearLayout 對比 RelativeLayout(百度)
22.優(yōu)化自定義 view(百度、樂視、小米)
23.ContentProvider(樂視)
24.fragment 生命周期
25.volley 解析(美團(tuán)、樂視)
26.Android Glide 源碼解析
27.Android 屬性動畫特性(樂視、小米)
由于篇幅有限,僅展示部分內(nèi)容,所有的知識點整理的詳細(xì)內(nèi)容,有需要的朋友可以加入粉絲裙:872206502進(jìn)行免費獲取
對于Android開發(fā)的朋友來說應(yīng)該是非常完整的面試文檔筆記了,為了更好地整理每個模塊,我參考了很多網(wǎng)上的優(yōu)質(zhì)博文和項目,力求不漏掉每一個知識點。很多朋友靠著這些內(nèi)容進(jìn)行復(fù)習(xí),拿到了BATJ等大廠的offer,這個文檔筆記也已經(jīng)幫助了很多的安卓開發(fā)者,希望也能幫助到你。
本文摘自 :https://blog.51cto.com/u