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