1瞭恰、重載(Overload)和重寫(xiě)(Override)的區(qū)別童谒。重載的方法能否根據(jù)返回類(lèi)型進(jìn)行區(qū)分?
答:方法的重載和重寫(xiě)都是實(shí)現(xiàn)多態(tài)的方式宜肉,區(qū)別在于前者實(shí)現(xiàn)的是編譯時(shí)的多態(tài)性橘霎,而后者實(shí)現(xiàn)的是運(yùn)行時(shí)的多態(tài)性荆针。重載發(fā)生在一個(gè)類(lèi)中腌且,同名的方法如果有不同的參數(shù)列表(參數(shù)類(lèi)型不同梗肝、參數(shù)個(gè)數(shù)不同或者二者都不同)則視為重載;重寫(xiě)發(fā)生在子類(lèi)與父類(lèi)之間铺董,重寫(xiě)要求子類(lèi)被重寫(xiě)方法與父類(lèi)被重寫(xiě)方法有相同的返回類(lèi)型统捶,比父類(lèi)被重寫(xiě)方法更好訪(fǎng)問(wèn),不能比父類(lèi)被重寫(xiě)方法聲明更多的異常(里氏代換原則)柄粹。重載對(duì)返回類(lèi)型沒(méi)有特殊的要求喘鸟。
2、兩個(gè)對(duì)象值相同(x.equals(y) == true)驻右,但卻可有不同的hash code什黑,這句話(huà)對(duì)不對(duì)?
答:不對(duì)堪夭,如果兩個(gè)對(duì)象x和y滿(mǎn)足x.equals(y) == true愕把,它們的哈希碼(hash code)應(yīng)當(dāng)相同。Java對(duì)于eqauls方法和hashCode方法是這樣規(guī)定的:(1)如果兩個(gè)對(duì)象相同(equals方法返回true)森爽,那么它們的hashCode值一定要相同恨豁;(2)如果兩個(gè)對(duì)象的hashCode相同,它們并不一定相同爬迟。當(dāng)然橘蜜,你未必要按照要求去做,但是如果你違背了上述原則就會(huì)發(fā)現(xiàn)在使用容器時(shí),相同的對(duì)象可以出現(xiàn)在Set集合中计福,同時(shí)增加新元素的效率會(huì)大大下降(對(duì)于使用哈希存儲(chǔ)的系統(tǒng)跌捆,如果哈希碼頻繁的沖突將會(huì)造成存取性能急劇下降)。
補(bǔ)充:關(guān)于equals和hashCode方法象颖,很多Java程序都知道佩厚,但很多人也就是僅僅知道而已,在Joshua Bloch的大作《Effective Java》(很多軟件公司说订,《Effective Java》抄瓦、《Java編程思想》以及《重構(gòu):改善既有代碼質(zhì)量》是Java程序員必看書(shū)籍,如果你還沒(méi)看過(guò)陶冷,那就趕緊去亞馬遜買(mǎi)一本吧)中是這樣介紹equals方法的:首先equals方法必須滿(mǎn)足自反性(x.equals(x)必須返回true)闺鲸、對(duì)稱(chēng)性(x.equals(y)返回true時(shí),y.equals(x)也必須返回true)埃叭、傳遞性(x.equals(y)和y.equals(z)都返回true時(shí)摸恍,x.equals(z)也必須返回true)和一致性(當(dāng)x和y引用的對(duì)象信息沒(méi)有被修改時(shí),多次調(diào)用x.equals(y)應(yīng)該得到同樣的返回值)赤屋,而且對(duì)于任何非null值的引用x立镶,x.equals(null)必須返回false。實(shí)現(xiàn)高質(zhì)量的equals方法的訣竅包括:1. 使用==操作符檢查“參數(shù)是否為這個(gè)對(duì)象的引用”类早;2. 使用instanceof操作符檢查“參數(shù)是否為正確的類(lèi)型”媚媒;3. 對(duì)于類(lèi)中的關(guān)鍵屬性,檢查參數(shù)傳入對(duì)象的屬性是否與之相匹配涩僻;4. 編寫(xiě)完equals方法后缭召,問(wèn)自己它是否滿(mǎn)足對(duì)稱(chēng)性、傳遞性逆日、一致性嵌巷;5. 重寫(xiě)equals時(shí)總是要重寫(xiě)hashCode;6. 不要將equals方法參數(shù)中的Object對(duì)象替換為其他的類(lèi)型室抽,在重寫(xiě)時(shí)不要忘掉@Override注解搪哪。
3、String 和StringBuilder坪圾、StringBuffer 的區(qū)別?
答:Java 平臺(tái)提供了兩種類(lèi)型的字符串:String和StringBuffer / StringBuilder晓折,它們可以?xún)?chǔ)存和操作字符串。其中String是只讀字符串兽泄,也就意味著String引用的字符串內(nèi)容是不能被改變的漓概。而StringBuffer和StringBuilder類(lèi)表示的字符串對(duì)象可以直接進(jìn)行修改。StringBuilder是JDK 1.5中引入的病梢,它和StringBuffer的方法完全相同胃珍,區(qū)別在于它是在單線(xiàn)程環(huán)境下使用的,因?yàn)樗乃蟹矫娑紱](méi)有被synchronized修飾,因此它的效率也比StringBuffer略高堂鲜。
4. 說(shuō)說(shuō)常見(jiàn)的集合有哪些吧?
Map 接口和 Collection 接口是所有集合框架的父接口:
Collection 接口的子接口包括:Set 接口和 List 接口护奈;
Map 接口的實(shí)現(xiàn)類(lèi)主要有:HashMap缔莲、TreeMap、Hashtable霉旗、ConcurrentHashMap 以及 Properties 等痴奏;
Set 接口的實(shí)現(xiàn)類(lèi)主要有:HashSet、TreeSet厌秒、LinkedHashSet 等读拆;
List 接口的實(shí)現(xiàn)類(lèi)主要有:ArrayList、LinkedList鸵闪、Stack 以及 Vector 等檐晕。
4.1 HashMap 和 Hashtable 的區(qū)別有哪些?(必問(wèn))
HashMap 沒(méi)有考慮同步蚌讼,是線(xiàn)程不安全的辟灰;Hashtable 使用了 synchronized 關(guān)鍵字,是線(xiàn)程安全的篡石;
前者允許 null 作為 Key芥喇;后者不允許 null 作為 Key。
4.2 HashMap 的底層實(shí)現(xiàn)你知道嗎凰萨?
在 Java8 之前继控,其底層實(shí)現(xiàn)是數(shù)組 + 鏈表實(shí)現(xiàn),Java8 使用了數(shù)組 + 鏈表 + 紅黑樹(shù)實(shí)現(xiàn)胖眷。此時(shí)你可以簡(jiǎn)單的在紙上畫(huà)圖分析:
4.3. ConcurrentHashMap 和 Hashtable 的區(qū)別武通? (必問(wèn))
ConcurrentHashMap 結(jié)合了 HashMap 和 HashTable 二者的優(yōu)勢(shì)。
HashMap 沒(méi)有考慮同步珊搀,hashtable 考慮了同步的問(wèn)題厅须。但是 hashtable 在每次同步執(zhí)行時(shí)都要鎖住整個(gè)結(jié)構(gòu)。
ConcurrentHashMap 鎖的方式是稍微細(xì)粒度的食棕。 ConcurrentHashMap 將 hash 表分為 16 個(gè)桶(默認(rèn)值)朗和,諸如 get,put,remove 等常用操作只鎖當(dāng)前需要用到的桶。
面試官:ConcurrentHashMap 的具體實(shí)現(xiàn)知道嗎簿晓?
該類(lèi)包含兩個(gè)靜態(tài)內(nèi)部類(lèi) HashEntry 和 Segment眶拉;前者用來(lái)封裝映射表的鍵值對(duì),后者用來(lái)充當(dāng)鎖的角色憔儿;
Segment 是一種可重入的鎖 ReentrantLock忆植,每個(gè) Segment 守護(hù)一個(gè) HashEntry 數(shù)組里得元素,當(dāng)對(duì) HashEntry 數(shù)組的數(shù)據(jù)進(jìn)行修改時(shí),必須首先獲得對(duì)應(yīng)的 Segment 鎖朝刊。
4.4. HashMap 的長(zhǎng)度為什么是 2 的冪次方耀里?
通過(guò)將 Key 的 hash 值與 length-1 進(jìn)行 & 運(yùn)算,實(shí)現(xiàn)了當(dāng)前 Key 的定位拾氓,2 的冪次方可以減少?zèng)_突(碰撞)的次數(shù)冯挎,提高 HashMap 查詢(xún)效率;
如果 length 為 2 的次冪 則 length-1 轉(zhuǎn)化為二進(jìn)制必定是 11111……的形式咙鞍,在于 h 的二進(jìn)制與操作效率會(huì)非常的快房官,而且空間不浪費(fèi);
如果 length 不是 2 的次冪续滋,比如 length 為 15翰守,則 length-1 為 14,對(duì)應(yīng)的二進(jìn)制為 1110疲酌,在于 h 與操作蜡峰,最后一位都為 0,而 0001朗恳,0011事示,0101,1001僻肖,1011肖爵,0111,1101 這幾個(gè)位置永遠(yuǎn)都不能存放元素了臀脏,空間浪費(fèi)相當(dāng)大劝堪。
更糟的是這種情況中,數(shù)組可以使用的位置比數(shù)組長(zhǎng)度小了很多揉稚,這意味著進(jìn)一步增加了碰撞的幾率秒啦,減慢了查詢(xún)的效率!這樣就會(huì)造成空間的浪費(fèi)搀玖。
4.5 Java 集合的快速失敗機(jī)制 “fail-fast”
它是 java 集合的一種錯(cuò)誤檢測(cè)機(jī)制余境,當(dāng)多個(gè)線(xiàn)程對(duì)集合進(jìn)行結(jié)構(gòu)上的改變的操作時(shí),有可能會(huì)產(chǎn)生 fail-fast 機(jī)制灌诅。
例如 :假設(shè)存在兩個(gè)線(xiàn)程(線(xiàn)程 1芳来、線(xiàn)程 2),線(xiàn)程 1 通過(guò) Iterator 在遍歷集合 A 中的元素猜拾,在某個(gè)時(shí)候線(xiàn)程 2 修改了集合 A 的結(jié)構(gòu)(是結(jié)構(gòu)上面的修改即舌,而不是簡(jiǎn)單的修改集合元素的內(nèi)容),那么這個(gè)時(shí)候程序就會(huì)拋出 ConcurrentModificationException 異常挎袜,從而產(chǎn)生 fail-fast 機(jī)制顽聂。
原因: 迭代器在遍歷時(shí)直接訪(fǎng)問(wèn)集合中的內(nèi)容肥惭,并且在遍歷過(guò)程中使用一個(gè) modCount 變量。集合在被遍歷期間如果內(nèi)容發(fā)生變化紊搪,就會(huì)改變 modCount 的值蜜葱。
每當(dāng)?shù)魇褂?hashNext()/next() 遍歷下一個(gè)元素之前,都會(huì)檢測(cè) modCount 變量是否為 expectedmodCount 值耀石,是的話(huà)就返回遍歷牵囤;否則拋出異常,終止遍歷娶牌。
解決辦法:
在遍歷過(guò)程中奔浅,所有涉及到改變 modCount 值得地方全部加上 synchronized馆纳;
使用 CopyOnWriteArrayList 來(lái)替換 ArrayList诗良。
4、List鲁驶、Set鉴裹、Map 是否繼承自Collection 接口?
答:List钥弯、Set 是径荔,Map 不是。Map是鍵值對(duì)映射容器脆霎,與List和Set有明顯的區(qū)別总处,而Set存儲(chǔ)的零散的元素且不允許有重復(fù)元素(數(shù)學(xué)中的集合也是如此),List是線(xiàn)性結(jié)構(gòu)的容器睛蛛,適用于按數(shù)值索引訪(fǎng)問(wèn)元素的情形鹦马。
5、說(shuō)出ArrayList忆肾、Vector荸频、LinkedList 的存儲(chǔ)性能和特性?
答:ArrayList 和Vector都是使用數(shù)組方式存儲(chǔ)數(shù)據(jù)客冈,此數(shù)組元素?cái)?shù)大于實(shí)際存儲(chǔ)的數(shù)據(jù)以便增加和插入元素旭从,它們都允許直接按序號(hào)索引元素,但是插入元素要涉及數(shù)組元素移動(dòng)等內(nèi)存操作场仲,所以索引數(shù)據(jù)快而插入數(shù)據(jù)慢和悦,Vector由于使用了synchronized 方法(線(xiàn)程安全),通常性能上較ArrayList 差渠缕,而LinkedList 使用雙向鏈表實(shí)現(xiàn)存儲(chǔ)(將內(nèi)存中零散的內(nèi)存單元通過(guò)附加的引用關(guān)聯(lián)起來(lái)摹闽,形成一個(gè)可以按序號(hào)索引的線(xiàn)性結(jié)構(gòu)褐健,這種鏈?zhǔn)酱鎯?chǔ)方式與數(shù)組的連續(xù)存儲(chǔ)方式相比付鹿,其實(shí)對(duì)內(nèi)存的利用率更高)澜汤,按序號(hào)索引數(shù)據(jù)需要進(jìn)行前向或后向遍歷,但是插入數(shù)據(jù)時(shí)只需要記錄本項(xiàng)的前后項(xiàng)即可舵匾,所以插入速度較快俊抵。Vector屬于遺留容器(早期的JDK中使用的容器,除此之外Hashtable坐梯、Dictionary徽诲、BitSet、Stack吵血、Properties都是遺留容器)谎替,現(xiàn)在已經(jīng)不推薦使用,但是由于ArrayList和LinkedListed都是非線(xiàn)程安全的蹋辅,如果需要多個(gè)線(xiàn)程操作同一個(gè)容器钱贯,那么可以通過(guò)工具類(lèi)Collections中的synchronizedList方法將其轉(zhuǎn)換成線(xiàn)程安全的容器后再使用(這其實(shí)是裝潢模式最好的例子,將已有對(duì)象傳入另一個(gè)類(lèi)的構(gòu)造器中創(chuàng)建新的對(duì)象來(lái)增加新功能)侦另。
補(bǔ)充:遺留容器中的Properties類(lèi)和Stack類(lèi)在設(shè)計(jì)上有嚴(yán)重的問(wèn)題秩命,Properties是一個(gè)鍵和值都是字符串的特殊的鍵值對(duì)映射,在設(shè)計(jì)上應(yīng)該是關(guān)聯(lián)一個(gè)Hashtable并將其兩個(gè)泛型參數(shù)設(shè)置為String類(lèi)型褒傅,但是Java API中的Properties直接繼承了Hashtable弃锐,這很明顯是對(duì)繼承的濫用。這里復(fù)用代碼的方式應(yīng)該是HAS-A關(guān)系而不是IS-A關(guān)系殿托,另一方面容器都屬于工具類(lèi)霹菊,繼承工具類(lèi)本身就是一個(gè)錯(cuò)誤的做法,使用工具類(lèi)最好的方式是HAS-A關(guān)系(關(guān)聯(lián))或USE-A關(guān)系(依賴(lài))支竹。同理旋廷,Stack類(lèi)繼承Vector也是不正確的。
6唾戚、Collection 和Collections 的區(qū)別柳洋?
答:Collection 是一個(gè)接口,它是Set叹坦、List等容器的父接口熊镣;Collections 是個(gè)一個(gè)工具類(lèi),提供了一系列的靜態(tài)方法來(lái)輔助容器操作募书,這些方法包括對(duì)容器的搜索绪囱、排序、線(xiàn)程安全化等等莹捡。
7鬼吵、List、Map篮赢、Set 三個(gè)接口齿椅,存取元素時(shí)琉挖,各有什么特點(diǎn)?
答:List以特定索引來(lái)存取元素涣脚,可有重復(fù)元素示辈。Set不能存放重復(fù)元素(用對(duì)象的equals()方法來(lái)區(qū)分元素是否重復(fù))。Map保存鍵值對(duì)(key-value pair)映射遣蚀,映射關(guān)系可以是一對(duì)一或多對(duì)一矾麻。Set和Map容器都有基于哈希存儲(chǔ)和排序樹(shù)的兩種實(shí)現(xiàn)版本,基于哈希存儲(chǔ)的版本理論存取時(shí)間復(fù)雜度為O(1)芭梯,而基于排序樹(shù)版本的實(shí)現(xiàn)在插入或刪除元素時(shí)會(huì)按照元素或元素的鍵(key)構(gòu)成排序樹(shù)從而達(dá)到排序和去重的效果险耀。
7.1、HashMap是線(xiàn)程安全的嗎玖喘?線(xiàn)程安全的Map都有哪些甩牺?性能最好的是哪個(gè)
7.2、HashMap的數(shù)據(jù)結(jié)構(gòu)是怎樣的芒涡?默認(rèn)大小是多少柴灯??jī)?nèi)部是怎么擴(kuò)容的卖漫?
8费尽、編寫(xiě)多線(xiàn)程程序有幾種實(shí)現(xiàn)方式?
答:Java 5以前實(shí)現(xiàn)多線(xiàn)程有兩種實(shí)現(xiàn)方法:一種是繼承Thread類(lèi)羊始;另一種是實(shí)現(xiàn)Runnable接口旱幼。兩種方式都要通過(guò)重寫(xiě)run()方法來(lái)定義線(xiàn)程的行為,推薦使用后者突委,因?yàn)镴ava中的繼承是單繼承柏卤,一個(gè)類(lèi)有一個(gè)父類(lèi),如果繼承了Thread類(lèi)就無(wú)法再繼承其他類(lèi)了匀油,顯然使用Runnable接口更為靈活缘缚。
補(bǔ)充:Java 5以后創(chuàng)建線(xiàn)程還有第三種方式:實(shí)現(xiàn)Callable接口,該接口中的call方法可以在線(xiàn)程執(zhí)行結(jié)束時(shí)產(chǎn)生一個(gè)返回值敌蚜,代碼如下所示:
9桥滨、線(xiàn)程的基本狀態(tài)以及狀態(tài)之間的關(guān)系?
除去起始(new)狀態(tài)和結(jié)束(finished)狀態(tài)弛车,線(xiàn)程有三種狀態(tài)齐媒,分別是:就緒(ready)、運(yùn)行(running)和阻塞(blocked)纷跛。其中就緒狀態(tài)代表線(xiàn)程具備了運(yùn)行的所有條件喻括,只等待CPU調(diào)度(萬(wàn)事俱備,只欠東風(fēng))贫奠;處于運(yùn)行狀態(tài)的線(xiàn)程可能因?yàn)镃PU調(diào)度(時(shí)間片用完了)的原因回到就緒狀態(tài)唬血,也有可能因?yàn)檎{(diào)用了線(xiàn)程的yield方法回到就緒狀態(tài)望蜡,此時(shí)線(xiàn)程不會(huì)釋放它占有的資源的鎖,坐等CPU以繼續(xù)執(zhí)行拷恨;運(yùn)行狀態(tài)的線(xiàn)程可能因?yàn)镮/O中斷泣特、線(xiàn)程休眠、調(diào)用了對(duì)象的wait方法而進(jìn)入阻塞狀態(tài)(有的地方也稱(chēng)之為等待狀態(tài))挑随;而進(jìn)入阻塞狀態(tài)的線(xiàn)程會(huì)因?yàn)樾菝呓Y(jié)束状您、調(diào)用了對(duì)象的notify方法或notifyAll方法或其他線(xiàn)程執(zhí)行結(jié)束而進(jìn)入就緒狀態(tài)。注意:調(diào)用wait方法會(huì)讓線(xiàn)程進(jìn)入等待池中等待被喚醒兜挨,notify方法或notifyAll方法會(huì)讓等待鎖中的線(xiàn)程從等待池進(jìn)入等鎖池膏孟,在沒(méi)有得到對(duì)象的鎖之前,線(xiàn)程仍然無(wú)法獲得CPU的調(diào)度和執(zhí)行拌汇。
10柒桑、Java 中有幾種類(lèi)型的流?
答:字節(jié)流噪舀,字符流魁淳。字節(jié)流繼承于InputStream、OutputStream与倡,字符流繼承于Reader界逛、Writer。在java.io 包中還有許多其他的流纺座,主要是為了提高性能和使用方便息拜。
11、你在開(kāi)發(fā)中都用到了那些設(shè)計(jì)模式净响?用在什么場(chǎng)合少欺?
答:面試被問(wèn)到關(guān)于設(shè)計(jì)模式的知識(shí)時(shí),可以?huà)畛S玫淖鞔鸩鱿停纾?/p>
1)工廠(chǎng)模式:工廠(chǎng)類(lèi)可以根據(jù)條件生成不同的子類(lèi)實(shí)例赞别,這些子類(lèi)有一個(gè)公共的抽象父類(lèi)并且實(shí)現(xiàn)了相同的方法,但是這些方法針對(duì)不同的數(shù)據(jù)進(jìn)行了不同的操作(多態(tài)方法)配乓。當(dāng)?shù)玫阶宇?lèi)的實(shí)例后仿滔,開(kāi)發(fā)人員可以調(diào)用基類(lèi)中的方法而不必考慮到底返回的是哪一個(gè)子類(lèi)的實(shí)例。
2)代理模式:給一個(gè)對(duì)象提供一個(gè)代理對(duì)象扰付,并由代理對(duì)象控制原對(duì)象的引用堤撵。實(shí)際開(kāi)發(fā)中,按照使用目的的不同羽莺,代理可以分為:遠(yuǎn)程代理实昨、虛擬代理、保護(hù)代理盐固、Cache代理荒给、防火墻代理丈挟、同步化代理、智能引用代理志电。
3)適配器模式:把一個(gè)類(lèi)的接口變換成客戶(hù)端所期待的另一種接口曙咽,從而使原本因接口不匹配而無(wú)法在一起使用的類(lèi)能夠一起工作。
4)模板方法模式:提供一個(gè)抽象類(lèi)挑辆,將部分邏輯以具體方法或構(gòu)造器的形式實(shí)現(xiàn)例朱,然后聲明一些抽象方法來(lái)迫使子類(lèi)實(shí)現(xiàn)剩余的邏輯。不同的子類(lèi)可以以不同的方式實(shí)現(xiàn)這些抽象方法(多態(tài)實(shí)現(xiàn))鱼蝉,從而實(shí)現(xiàn)不同的業(yè)務(wù)邏輯洒嗤。
除此之外,還可以講講上面提到的門(mén)面模式魁亦、橋梁模式渔隶、單例模式、裝潢模式(Collections工具類(lèi)里面的synchronizedXXX方法把一個(gè)線(xiàn)程不安全的容器變成線(xiàn)程安全容器就是對(duì)裝潢模式的應(yīng)用洁奈,而Java IO里面的過(guò)濾流(有的翻譯成處理流)也是應(yīng)用裝潢模式的經(jīng)典例子)等间唉,反正原則就是揀自己最熟悉的用得最多的作答,以免言多必失利术。
參考文章
http://www.reibang.com/p/08c69641c5df
https://blog.csdn.net/jackfrued/article/details/17339393
https://blog.csdn.net/u010842515/article/details/68490245
https://mp.weixin.qq.com/s/sca3lbMMqqEuR10Pd5bcDw