重磅!!面试季--最新面试题总结出厂,附题解,后期持续分享!
一、情話部分
小姐姐: 為什么有很多人在感情中付出很多,卻得不到想要的結(jié)果?
你答: 我聽過一個這樣的故事:講的是蚯蚓一家人,有一天,蚯蚓爸爸特別無聊,就把自己切成了倆段愉快的打羽毛球去了,蚯蚓媽媽見狀,把自己切成了四段,打麻將去了,蚯蚓哥哥接近狂熱,把自己切成很多段,結(jié)果死掉了,因為他想踢足球。蚯蚓哥哥的死震驚了整個蚯蚓界,各蚯蚓專家呼吁大家要謹慎使用自己的能力。蚯蚓哥哥的死同時對蚯蚓一家造成了不可磨滅的傷害,蚯蚓弟弟為了彌補家庭的殘缺,決定把自己切成倆段。第二天蚯蚓弟弟也死掉了。你知道為什么嗎?
**小姐姐:**嗯?不知道(如果小姐姐知道,你就夸她聰明咯)
**你:**因為蚯蚓弟弟是豎著切的。
這個故事告訴我們,有時候呀,我們總是在應(yīng)該動腦的時候,卻動了情!!!
二、闖關(guān)階段
自我介紹:( 您好(人多就說大家好),很榮幸有機會參加此次面試,希望我今天能有好的表現(xiàn),現(xiàn)在請允許我介紹一下自己:我叫變壞,今年18歲,畢業(yè)于牛客大學軟件工程專業(yè)(或者說是XX大學軟件工程專業(yè)的應(yīng)屆生),在大學期間專業(yè)課學習了java這門編程語言,自己在網(wǎng)上也學習了一些相關(guān)的技術(shù),在校期間自己也曾和同學使用java開發(fā)過一些項目,在學校也曾考取過相關(guān)的證書,獲得過一些比賽的獎,大學期間還擔任過課代表,由于畢業(yè)將近,本人決定踏上社會道路,因此在牛客平臺看到貴公司的招聘,在此之前也曾在網(wǎng)上了解過貴公司(不要去問公司業(yè)務(wù),網(wǎng)上都可以查的),巴拉巴拉吹一吹。從以上簡單的自我介紹里,我希望公司能給我一個展示自己能力的機會)
1 多線程的幾種實現(xiàn)方式
繼承Thread類,實現(xiàn)Runnable接口,實現(xiàn)Callable接口,線程池
下面是我的csdn博客的一篇文章,詳細說明了:https://blog.csdn.net/sihai12345/article/details/80256322
2 線程join()方法
Thread中,join()方法的作用是調(diào)用線程等待該線程完成后,才能繼續(xù)用下運行。
public static void main(String[] args) throws InterruptedException{System.out.println("main start");Thread t1 = new Thread(new Worker("thread-1"));t1.start();t1.join();System.out.println("main end");}在上面的例子中,main線程要等到t1線程運行結(jié)束后,才會輸出“main end”。如果不加t1.join(),main線程和t1線程是并行的。而加上t1.join(),程序就變成是順序執(zhí)行了。
我們在用到j(luò)oin()的時候,通常都是main線程等到其他多個線程執(zhí)行完畢后再繼續(xù)執(zhí)行。其他多個線程之間并不需要互相等待。
下面這段代碼并沒有實現(xiàn)讓其他線程并發(fā)執(zhí)行,線程是順序執(zhí)行的。
public static void main(String[] args) throws InterruptedException{System.out.println("main start");Thread t1 = new Thread(new Worker("thread-1"));Thread t2 = new Thread(new Worker("thread-2"));t1.start();//等待t1結(jié)束,這時候t2線程并未啟動t1.join();//t1結(jié)束后,啟動t2線程t2.start();//等待t2結(jié)束t2.join();System.out.println("main end");}為了讓t1、t2線程并行,我們可以稍微改一下代碼,下面給出完整的代碼:
public class JoinTest {public static void main(String[] args) throws InterruptedException{System.out.println("main start");Thread t1 = new Thread(new Worker("thread-1"));Thread t2 = new Thread(new Worker("thread-2"));t1.start();t2.start();t1.join();t2.join();System.out.println("main end");} }class Worker implements Runnable {private String name;public Worker(String name){this.name = name;}@Overridepublic void run(){for (int i = 0; i < 10; i++){try{Thread.sleep(1l);}catch (InterruptedException e){e.printStackTrace();}System.out.println(name);}}}3 ArrayList的remove操作
ArrayList有倆個remove()重載方法,一個參數(shù)是int類型,另一個參數(shù)是Object類型,remove(1)是刪除索引為1的元素,remove(new Integer(1))是刪除元素1,底層是用equals進行比較的。
先看迭代器的 next 方法
public E next() {// 這個方法主要是檢查光標是否越界的checkForComodification();int i = cursor;if (i >= size)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i]; } /** * 在對一個集合對象進行跌代操作的同時,并不限制對集合對象的元素進行操作 * 這些操作包括一些可能引起跌代錯誤的add()或remove()等危險操作。 * 在AbstractList中,使用了一個簡單的機制來規(guī)避這些風險。 * 這就是modCount和expectedModCount的作用所在 */ final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException(); }我們可以看到,list 每次獲取下一個對象前都要去檢查一下光標是否越界。在 ArrayList 的所有涉及結(jié)構(gòu)變化的方法中都增加 modCount 的值,包括:add()、remove()、addAll()、removeRange() 及 clear() 方法。這些方法每調(diào)用一次,modCount 的值就加 1。而變量 expectedModCount 在迭代開始時便會被賦值成 modCount 的值。所以在循環(huán)遍歷中,改變結(jié)構(gòu)變化的方法,例如 add()、remove() 都會是 modCount 增長 1 ,而 expectedModCount 卻不會變化。
注意,以上講的涉及到結(jié)構(gòu)變化的方法是 ArrayList 的方法,不是其內(nèi)部類 Itr 的方法。
來看一下 ArrayList 的 remove 方法
public E remove(int index) {rangeCheck(index);modCount++;E oldValue = elementData(index);int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its workreturn oldValue; } public boolean remove(Object o) {if (o == null) {for (int index = 0; index < size; index++)if (elementData[index] == null) {fastRemove(index);return true;}} else {for (int index = 0; index < size; index++)if (o.equals(elementData[index])) {fastRemove(index);return true;}}return false; }private void fastRemove(int index) {modCount++;int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its work }從上面源碼中我們不難發(fā)現(xiàn),ArrayList 中兩個 remove() 方法都對 modCount 進行了自增,那么我們在用迭代器迭代的時候,若是刪除 末尾 的元素,則會造成 modCount 和 expectedModCount 的不一致導致異常拋出。
為什么對倒數(shù)第二個元素進行刪除不會報異常,而對其他位置的刪除會報異常?
我們來看一下 ArrayList 中的內(nèi)部類 Itr 。我們在調(diào)用迭代器的 Next() 方法之前會先調(diào)用 hasNext() 方法。
public boolean hasNext() {return cursor != size; }從代碼上我們可以看出判斷條件是當 cursor != size 的時候,才會進行下一次循環(huán),而 cursor 參數(shù)是我們迭代循環(huán)的下標,在我們刪除倒數(shù)第二個元素后,此時 list 的大小減了 1,再進入下一次循環(huán)后會出現(xiàn) cursor == size ,也就是 hasNext() 便會返回 false 終止了循環(huán)。實際上 modCount 的數(shù)值也增加了 1,只不過循環(huán)沒發(fā)執(zhí)行到那里,所以異常也就不會被拋出來了。
for 下標遍歷刪除
從源碼上我們可以看出,在利用 for 下標進行遍歷的時候,并不會觸發(fā) checkForComodification() 方法,所以此時只要要刪除的位置比列表大小小時都不會出錯。
public E remove(int index) {rangeCheck(index);modCount++;E oldValue = elementData(index);int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its workreturn oldValue; }在 ArrayList 源碼介紹中,作者是推薦使用 for ( int i; i < size; i++) 方式去遍歷,而不是 foreach 或者迭代,這個主要是因為 list 接口實現(xiàn)了 RandomAccess 接口。 實現(xiàn)這個接口的集合是隨機無序的,所以遍歷的時候一般使用上述的 for,記住一點就可以了所有實現(xiàn)了 RandomAccess 接口的集合都是用一般 for 就可以了(可以通過 api 查看那些集合實現(xiàn)了 RandomAccess)。
Iterator 迭代遍歷刪除
這里我們將的 Iterator 遍歷刪除調(diào)用的方法不是 ArrayList 的 remove 方法,而是其內(nèi)部類的 remove 方法
我們看源碼不難發(fā)現(xiàn),在 Itr 類中,屬性 expectedModCount 在調(diào)用外部的 remove() 方法后再次被賦值,此時 expectedModCount 是等于 modCount 的。
public void remove() {if (lastRet < 0)throw new IllegalStateException();// 這里檢查時候還沒有進行刪除操作checkForComodification();try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;// 先進行了 remove 操作后 再重新對 expectedModCount 進行賦值expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();} }所以在使用 Iterator 進行遍歷刪除時不會出現(xiàn) ConcurrentModificationException 異常。
- 原文:https://blog.csdn.net/qq_35108975/article/details/82971437
4 HashMap為啥不安全
resize死循環(huán),fail-fast(快速失敗)
具體查看:https://www.jianshu.com/p/e2f75c8cce01
5 HashMap1.7和1.8區(qū)別
1.7數(shù)組+鏈表,頭插入,1.8數(shù)組+鏈表+紅黑樹,尾插入。resize方法、hash計算方式、擴容后的位置計算方式等
具體詳解:https://blog.csdn.net/qq_30683329/article/details/80454518
6 HashMap如何擴容及Put方法
具體詳情:https://blog.csdn.net/fendianli6830/article/details/81102709
7 TreeMap
默認按照Key的字典序升序排列,底層紅黑樹+compareTo()方法,大致就是和根節(jié)點比較,小于根節(jié)點往左子樹繼續(xù)去比較,大于根節(jié)點往右子樹去比較咯等等
大佬文章:https://www.cnblogs.com/chenssy/p/3746600.html
8 concurrentHashMap底層原理
推薦文章:https://blog.csdn.net/sihai12345/article/details/79383766
9 如何確保一個集合不被修改
使用Collections.unmodifiableCollection(Collection c)方法創(chuàng)建只讀集合
10 Iterator和ListIterator有什么區(qū)別
前者只能遍歷不能修改,后者可以修改元素并且可以逆向遍歷、定位當前索引位置,但后者只能用于List及其子類型
11 快速失敗和安全失敗
fail-fast:遍歷時對集合進行增刪改會拋出Concurrent Modification Exception異常,一般的java.util包下的集合用的就是快速失敗。安全失敗就是采用復制方式,修改原集合,雖然不會報錯,但是也沒辦法訪問修改后的元素。一般在java.util.concurrent包下集合用的就是安全失敗
具體查看:https://mp.weixin.qq.com/s/l9SDwQuFKeCcufI3KJCWpw
12 如果clone單例模式的對象會怎樣
不行,這里必須要實現(xiàn)Cloneable接口,所以需要單例的類不能去實現(xiàn)Clonable接口。反射應(yīng)該可以去獲取私有的構(gòu)造方法從而破壞單例
13 hibernate和mybatis區(qū)別
相同方面:ORM、都支持jdbc事務(wù)
不同點:sql方面、緩存方面
具體查看:https://mp.weixin.qq.com/s/h7tAk1IjdMi5SSNjRZE50g
14 mysql聯(lián)合索引和聚集索引
聯(lián)合索引就是多列組成的索引,聚集索引CLUSTERED,聚集索引的順序與數(shù)據(jù)真實的物理存儲順序一致,特別快,主鍵!=聚集索引
15 行鎖和表鎖
表鎖:不會出現(xiàn)死鎖,發(fā)生鎖沖突幾率高,并發(fā)低。
行鎖:會出現(xiàn)死鎖,發(fā)生鎖沖突幾率低,并發(fā)高
16 b樹索引和Hash索引區(qū)別
大量不同數(shù)據(jù)查找,hash索引比B樹索引效率高,hash索引不支持聯(lián)合索引的最左匹配規(guī)則,hash索引不支持排序,hash索引不支持模糊查找
17 軟連接硬鏈接
軟連接:新建一個文件來指向別的文件,原文件刪除則不可用,可跨文件系統(tǒng)。
硬鏈接:原來的inode link count域再增加1(在Linux的文件系統(tǒng)中,保存在磁盤分區(qū)中的文件不管是什么類型都給它分配一個編號,稱為索引節(jié)點號inode ),不可跨文件系統(tǒng),刪除原文件也可繼續(xù)使用。ln是創(chuàng)建硬鏈接 ln -s是創(chuàng)建軟連接)
18 linux查看進程的命令
ps命令 -A:所有的進程均顯示出來、-a顯示現(xiàn)行終端機下的所有進程,包括其他用戶的進程 、-u以用戶為主的進程狀態(tài)
linux常用命令:https://mp.weixin.qq.com/s/ZqHy0_m4tNMAQT53mKlc7g
總結(jié)
以上是生活随笔為你收集整理的重磅!!面试季--最新面试题总结出厂,附题解,后期持续分享!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于这件事,我有话要说!
- 下一篇: 多问问自己想成为什么样的人