- 相關推薦
最新2017阿里巴巴招聘筆試題
以下是CN人才網小編為大家整理的最新2017阿里巴巴招聘筆試題,歡迎閱讀參考。
1、多線程什么情況下執行wait?
答:在同步代碼塊中,即對象只有獲得了互斥鎖之后才可以調用wait()方法。
延伸學習(1):
sleep( )和wait( n)、wait( )的區別:
sleep方法:是Thread類的靜態方法,當前線程將睡眠n毫秒,線程進入阻塞狀態。當睡眠時間到了,會解除阻塞,進行可運行狀態,等待CPU的到來。睡眠不釋放鎖(如果有的話)
wait方法:是Object的方法,必須與synchronized關鍵字一起使用,線程進入阻塞狀態,當notify或者notifyall被調用后,會解除阻塞。但是,只有重新占用互斥鎖之后才會進入可運行狀態。睡眠時,釋放互斥鎖。
join( )方法:
當前線程調用,則其它線程全部停止,等待當前線程執行完畢,接著執行。
suspend( )和resume( )方法:
兩個方法配套使用,前者使線程進入阻塞狀態,并且不會自動恢復,必須等待resume( )方法被調用,才能使得線程重新進入可執行狀態。
典型用法,用于等待另一個線程產生的結果的情形,測試發現結果還沒有產生后,讓線程阻塞。當另一個線程產生了結果后,調用resume( )使其恢復。
yield() 方法:
yield() 使得線程放棄當前分得的 CPU 時間,但是不使線程阻塞,即線程仍處于可執行狀態,隨時可能再次分得 CPU 時間。調用 yield() 的效果等價于調度程序認為該線程已執行了足夠的時間從而轉到另一個線程。
延伸學習(2):
線程的的生命周期:創建狀態、就緒狀態(可運行狀態)、運行狀態、阻塞狀態、消亡狀態。
2、Spring容器如何加載?
答:
在應用程序web.xml中做了以下配置信息時,當啟動Web容器時就會自動加載spring容器。
ContextLoaderListener!!!
org.springframework.web.context.ContextLoaderListener
[html] view plain copy
org.springframework.web.context.ContextLoaderListener
ContextLoaderListener類實現了javax.servlet.ServletContextListener接口并且繼承了org.springframework.web.context.ContextLoader類。
ServletContextListener事件類是Web容器的一部分,處理Web應用的Servlet上下文(context)的監聽。實現ServletContextListener接口中的contextInitialized和contextDestroyed方法。當Web容器啟動時會自動調用contextInitialized方法,進行初始化Spring Web應用程序上下文,主要加載web.xml中contextConfigLocation的配置文件;當Web容器關閉之前會調用contextDestroyed方法,進行銷毀Spring Web應用程序上下文。ContextLoader類實現了Spring上下文初始化的工作,執行initWebApplicationContext方法返回WebApplicationContext。
延伸學習:
如果要spring-mvc的話,需要在web.xml文件中配置如下:
DispatchServlet!!!
org.springframework.web.servlet.DispatchServlet
[html] view plain copy
simpleSpringMVC/servlet-name>
org.springframework.web.servlet.DispatchServlet
1
simpleSpringMVC
*.htm
3、Servlet生命周期(什么時候destory)?
答:Servlet的生命周期是由Servlet容器(即Web服務器)來控制的,通過簡單的概括可以分為4步:
(1)Servlet類加載
(2)實例化Servlet
(3)Servlet提供服務
(4)銷毀Servlet
當Web應用被終止時,Servlet容器會先調用Web應用中所有的Servlet對象的destroy( )方法,然后再銷毀Servlet對象。
4、10G數據,每一條是一個qq號,統計出現頻率最多的qq號。
答:
首先你要注意到,數據存在服務器,存儲不了(內存存不了),要想辦法統計每一個qq出現的次數。
比如,因為內存是1g,首先 你用hash 的方法,把qq分配到10個(這個數字可以變動,比較)文件(在硬盤中)。
相同的qq肯定在同一個文件中,然后對每一個文件,只要保證每一個文件少于1g的內存,統計每個qq的次數,可以使用hash_map(qq, qq_count)實現。然后,記錄每個文件的最大訪問次數的qq,最后,從10個文件中找出一個最大,即為所有的最大。
那若面試官問有沒有更高效率的解法之類的?這時,你可以優化一下,但是這個速度很快,hash函數,速度很快,他肯定會問,你如何設計,用bitmap也行。
5、hashmap實現原理
HashMap解決hash沖突的過程如下:
HashMap 采用一種所謂的“Hash 算法”來決定每個元素的存儲位置。當程序執行 map.put(String,Obect)方法 時,系統將調用String的 hashCode() 方法得到其 hashCode 值——每個 Java 對象都有 hashCode() 方法,都可通過該方法獲得它的 hashCode 值。得到這個對象的 hashCode 值之后,系統會根據該 hashCode 值來決定該元素的存儲位置。源碼如下:
[java] view plain copy
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
//判斷當前確定的索引位置是否存在相同hashcode和相同key的元素,如果存在相同的hashcode和相同的key的元素,那么新值覆蓋原來的舊值,并返回舊值。
//如果存在相同的hashcode,那么他們確定的索引位置就相同,這時判斷他們的key是否相同,如果不相同,這時就是產生了hash沖突。
//Hash沖突后,那么HashMap的單個bucket里存儲的不是一個 Entry,而是一個 Entry 鏈。
//系統只能必須按順序遍歷每個 Entry,直到找到想搜索的 Entry 為止——如果恰好要搜索的 Entry 位于該 Entry 鏈的最末端(該 Entry 是最早放入該 bucket 中),
//那系統必須循環到最后才能找到該元素。
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
上面程序中用到了一個重要的內部接口:Map.Entry,每個 Map.Entry 其實就是一個 key-value 對。從上面程序中可以看出:當系統決定存儲 HashMap 中的 key-value 對時,完全沒有考慮 Entry 中的 value,僅僅只是根據 key 來計算并決定每個 Entry 的存儲位置。這也說明了前面的結論:我們完全可以把 Map 集合中的 value 當成 key 的附屬,當系統決定了 key 的存儲位置之后,value 隨之保存在那里即可.HashMap程序經過我改造,我故意的構造出了hash沖突現象,因為HashMap的初始大小16,但是我在hashmap里面放了超過16個元素,并且我屏蔽了它的resize()方法。不讓它去擴容。這時HashMap的底層數組Entry[] table結構如下:
Hashmap里面的bucket出現了單鏈表的形式,散列表要解決的一個問題就是散列值的沖突問題,通常是兩種方法:鏈表法和開放地址法。鏈表法就是將相同hash值的對象組織成一個鏈表放在hash值對應的槽位;開放地址法是通過一個探測算法,當某個槽位已經被占據的情況下繼續查找下一個可以使用的槽位。java.util.HashMap采用的鏈表法的方式,鏈表是單向鏈表。形成單鏈表的核心代碼如下:
[java] view plain copy
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry e = table[bucketIndex];
table[bucketIndex] = new Entry(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
上面方法的代碼很簡單,但其中包含了一個設計:系統總是將新添加的 Entry 對象放入 table 數組的 bucketIndex 索引處——如果 bucketIndex 索引處已經有了一個 Entry 對象,那新添加的 Entry 對象指向原有的 Entry 對象(產生一個 Entry 鏈),如果 bucketIndex 索引處沒有 Entry 對象,也就是上面程序代碼的 e 變量是 null,也就是新放入的 Entry 對象指向 null,也就是沒有產生 Entry 鏈。
HashMap里面沒有出現hash沖突時,沒有形成單鏈表時,hashmap查找元素很快,get()方法能夠直接定位到元素,但是出現單鏈表后,單個bucket 里存儲的不是一個 Entry,而是一個 Entry 鏈,系統只能必須按順序遍歷每個 Entry,直到找到想搜索的 Entry 為止——如果恰好要搜索的 Entry 位于該 Entry 鏈的最末端(該 Entry 是最早放入該 bucket 中),那系統必須循環到最后才能找到該元素。
當創建 HashMap 時,有一個默認的負載因子(load factor),其默認值為 0.75,這是時間和空間成本上一種折衷:增大負載因子可以減少 Hash 表(就是那個 Entry 數組)所占用的內存空間,但會增加查詢數據的時間開銷,而查詢是最頻繁的的操作(HashMap 的 get() 與 put() 方法都要用到查詢);減小負載因子會提高數據查詢的性能,但會增加 Hash 表所占用的內存空間。
6、數組和鏈表的比較
答:
數組靜態分配內存,鏈表動態分配內存;
數組在內存中連續,鏈表不連續;
數組元素在棧區,鏈表元素在堆區;
數組利用下標定位,時間復雜度為O(1),鏈表定位元素時間復雜度O(n);
數組插入或刪除元素的時間復雜度O(n),鏈表的時間復雜度O(1)。
7、ArrayList和Linkedlist對比
答:
ArrayList和LinkedList在性能上各有優缺點,都有各自所適用的地方,總的說來可以描述如下:
1.對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內部數組中增加一項,指向所添加的元素,偶爾可能會導致對數組重新進行分配;而對LinkedList而言,這個開銷是統一的,分配一個內部Entry對象。
2.在ArrayList的中間插入或刪除一個元素意味著這個列表中剩余的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。
3.LinkedList不支持高效的隨機元素訪問。
4.ArrayList的空間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間
可以這樣說:當操作是在一列數據的后面添加數據而不是在前面或中間,并且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能;當你的操作是在一列數據的前面或中間添加或刪除數據,并且按照順序訪問其中的元素時,就應該使用LinkedList了。
程序員們,你答對了幾題,有實力進入阿里巴巴嗎?可以留言與我們討論哦!
【最新阿里巴巴招聘筆試題】相關文章:
醫院招聘護士常見考試題目05-11
幼兒教師招聘考試題庫09-13
最新防災減災知識測試題04-26
最新的抖音主播簡短的招聘文案11-16
最新公共場所從業人員衛生知識培訓試題08-10
英語試題08-17
最新英語CET4聽力試題練習(通用5篇)03-18
成人高考高升專《語文》模擬試題試題11-12
招聘實習總結08-22
招聘簡歷模板10-30