校招的日子結束了,結果也算圓滿。忙碌了一陣子,現在終於可以安安靜靜的做做項目看看書寫寫論文了。下面對這段時間面試遇到的問題並結合網上各位的大神秒下的面試題做個總結,本文會持續更新,希望能在面試中助各位一臂之力!
Java基礎:
1、內存洩露的原因:
- 資源對象沒關閉。
如Cursor、File等資源。他們會在finalize中關閉,但這樣效率太低。容易造成內存洩露。
SQLiteCursor,當數據量大的時候容易洩露
- 使用Adapter時,沒有使用系統緩存的converView。
- 即時調用recycle()釋放不再使用的Bitmap。
適當降低Bitmap的采樣率,如:
BitmapFactory.Options options = newBitmapFactory.Options();
options.inSampleSize = 2;//圖片寬高都為原來的二分之一,即圖片為原來的四分之一
Bitmap bitmap =BitmapFactory.decodeStream(cr.openInputStream(uri), null, options); preview.setImageBitmap(bitmap);
- 使用application的context來替代activity相關的context。
盡量避免activity的context在自己的范圍外被使用,這樣會導致activity無法釋放。
- 注冊沒取消造成內存洩露
如:廣播
- 集合中的對象沒清理造成的內存洩露我們通常把一些對象的引用加入到了集合中,當我們不需要該對象時,並沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,那情況就更嚴重了。
- Handler應該申明為靜態對象, 並在其內部類中保存一個對外部類的弱引用。如下:
static class MyHandler extends Handler
{
WeakReference<Activity > mActivityReference;
MyHandler(Activity activity)
{
mActivityReference= new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg)
{
final Activity activity = mActivityReference.get();
if (activity != null)
{
mImageView.setImageBitmap(mBitmap);
}
}
}
2、ArrayList和LinkedList的區別
- ArrayList初試大小為10,大小不夠會調用grow擴容:length = length + (length >> 1)
- LinkedList中Node first,last。分別指向頭尾
ArrayList和LinkedList在性能上各 有優缺點,都有各自所適用的地方,總的說來可以描述如下:
- 對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對 ArrayList而言,主要是在內部數組中增加一項,指向所添加的元素,偶爾可能會導致對數組重新進行分配;而對LinkedList而言,這個開銷是 統一的,分配一個內部Entry對象。
- 在ArrayList的 中間插入或刪除一個元素意味著這個列表中剩余的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。
- LinkedList不 支持高效的隨機元素訪問。
- ArrayList的空 間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間
可以這樣說:當操作是在一列 數據的後面添加數據而不是在前面或中間,並且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能;當你的操作是在一列數據的前面或中 間添加或刪除數據,並且按照順序訪問其中的元素時,就應該使用LinkedList了。
3、hashmap和hashtable的不同
- 繼承不同。
public class Hashtable extends Dictionary implements Map
public class HashMap extends AbstractMap implements Map
- Hashtable 中的方法是同步的,而HashMap中的方法在缺省情況下是非同步的。在多線程並發的環境下,可以直接使用Hashtable,但是要使用HashMap的話就要自己增加同步處理了。
- Hashtable中,key和value都不允許出現null值。
在HashMap中,null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為null。當get()方法返回null值時,即可以表示 HashMap中沒有該鍵,也可以表示該鍵所對應的值為null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵, 而應該用containsKey()方法來判斷。
- 兩個遍歷方式的內部實現上不同。
Hashtable、HashMap都使用了 Iterator。而由於歷史原因,Hashtable還使用了Enumeration的方式 。
- 哈希值的使用不同,HashTable直接使用對象的hashCode。而HashMap重新計算hash值。
6.Hashtable和HashMap它們兩個內部實現方式的數組的初始大小和擴容的方式。HashTable中hash數組默認大小是11,增加的方式是 old*2+1。HashMap中hash數組的默認大小是16,而且一定是2的指數。
4、Iterator和Enumeration的不同
- 函數接口不同
Enumeration只有2個函數接口。通過Enumeration,我們只能讀取集合的數據,而不能對數據進行修改。 Iterator只有3個函數接口。Iterator除了能讀取集合的數據之外,也能數據進行刪除操作。
- Iterator支持fail-fast機制,而Enumeration不支持。 Enumeration 是JDK 1.0添加的接口。使用到它的函數包括Vector、Hashtable等類,這些類都是JDK 1.0中加入的,Enumeration存在的目的就是為它們提供遍歷接口。Enumeration本身並沒有支持同步,而在Vector、Hashtable實現Enumeration時,添加了同步。而Iterator 是JDK 1.2才添加的接口,它也是為了HashMap、ArrayList等集合提供遍歷接口。Iterator是支持fail-fast機制的:當多個線程對同一個集合的內容進行操作時,就可能會產生fail-fast事件。
ail-fast 機制是java集合(Collection)中的一種錯誤機制。當多個線程對同一個集合的內容進行操作時,就可能會產生fail-fast事件。例如:當某一個線程A通過iterator去遍歷某集合的過程中,若該集合的內容被其他線程所改變了;那麼線程A訪問集合時,就會拋出ConcurrentModificationException異常,產生fail-fast事件。
5、接口的注意點
- 接口中的字段全部默認為 public static類型。
- 接口中的方法全部默認為 public類型。
- 接口中可以申明內部類,而默認為public static,正因為是static,只是命名空間屬於接口,代碼邏輯不屬於接口。所以不違法接口定義。
- 接口本身可以申明為public或者缺省。
- 抽象類繼承自某接口。如果在抽象類中實現了父類(接口)中的方法,在其子類可以不用實現,否則在子類必須實現。
6、final方法
將方法聲明為final那有兩個原因,第一就是說明你已經知道這個方法提供的功能已經滿足你要求,不需要進行擴展,並且也不允許任何從此類繼承的類來覆寫這個方法,但是繼承仍然可以繼承這個方法,也就是說可以直接使用。第二就是允許編譯器將所有對此方法的調用轉化為inline調用的機制,它會使你在調用final方法時,直接將方法主體插入到調用處,而不是進行例行的方法調用,例如保存斷點,壓棧等,這樣可能會使你的程序效率有所提高,然而當你的方法主體非常龐大時,或你在多處調用此方法,那麼你的調用主體代碼便會迅速膨脹,可能反而會影響效率,所以你要慎用final進行方法定義。
Android知識點
1、Handler機制
- Handler對Activity finish影響。
在開發的過程中碰到一個棘手的問題,調用Activity.finish函數Acitivity沒有執行生命周期的ondestory函數,後面查找半天是因為有一個handler成員,因為它有一個delay消息沒有處理,調用Activity.finish,Activity不會馬上destory,所以記得在Ativity finish前清理一下handle中的未處理的消息,這樣Activity才會順利的destory
- Looper
通過調用Looper.prepare()創建Looper()對象並綁定到ThreadLocal變量中。
Looper裡面包含了messageQueue。
構造器如下:
private Looper()
{
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
- loop()函數
1)從Looper中取出MessageQueue;
2)循環從MessageQueue中取出Message;
3)從Message中取出Target(Handler對象);
4)調用tartget的dispatchMessage分發消息。
- Handler對象
重要成員變量:
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback; //用於回調
Handler對象在發送消息的時候,將MSG的target變量設為自己。這樣在Looper對象循環取出msg的時候就可以調用對應handler的dispatchMessage()。此函數分發消息的優先級如下:
Message在創建的時候調用Obtain設置了Callback。
Handler在創���的時候傳入了Callback。
交給Handler子類的HandleMessage處理(通常的做法)。
2、Android啟動模式
standard和singleTop模式。
這兩種比較簡單。創建Activity放入當前的任務棧中,若當前是singleInstace,則放入設置的任務棧中。其中如果Activity在棧頂,則調用onNewIntent。
singletask:棧內復用模式。不是在當前任務棧中查找是否存在,實際過程如下:
- 查找該Activity所需的任務棧是否存在(由taskAffinity控制,或者默認為包名)。
- 在任務棧當中查找該Activity是否存在。
這裡面存在任務棧的切換,也就是當開啟的singtask類型的Activity不屬於當前任務棧時,則會切換到其任務棧。
singleInstance:單實例模式。
包含了singleTask的所有特性,另外加上:設置為該模式的Activity,只能單獨存在於一個任務棧中。當有兩個singleInstace的Activity設置成同樣的任務棧時,會出現兩個同名的任務棧,分別用來存放同名的Activity。
注:在任何跳轉的時候,首先調用本Activity的onPause,然後跳轉。如果被跳轉的activity由於啟動方式而沒創建新的實例,則會先調用onNewIntent,然後按照正常的生命周期調用。
如
1:A→B,A:onPause;B:onCreate,onStart,onResume。
2:A(singleTop)→A,A:onPause;A:onSaveInstanceState;A:onResume。
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11