java高頻面試題附答案(2023最新)




一.java基礎(chǔ)
1.八大基礎(chǔ)類型
數(shù)字型: 字節(jié)類型(byte)、短整型short、整型int、長(zhǎng)整型Long、單精度浮點(diǎn)數(shù)float、雙精度浮點(diǎn)數(shù)double
字符型: 字符類型char、
布爾型: 布爾類型boolean、
2.java三大特性
封裝: 使用private關(guān)鍵字,讓對(duì)象私有,防止無關(guān)的程序去使用。
繼承: 繼承某個(gè)類,使子類可以使用父類的屬性和方法。
多態(tài): 同一個(gè)行為,不同的子類具有不同的表現(xiàn)形式。
3.重載和重寫的區(qū)別
重載: 發(fā)生在同一類中,函數(shù)名必須一樣,參數(shù)類型、參數(shù)個(gè)數(shù)、參數(shù)順序、返回值、修飾符可以不一樣。
重寫: 發(fā)生在父子類中,函數(shù)名、參數(shù)、返回值必須一樣,訪問修飾符必須大于等于父類,異常要小于等于父類,父類方法是private不能重寫。
4.pubilc、protected、(dafault)不寫、private修飾符的作用范圍
pubilc: 同類、同包、子類、不同包都可以使用。
protected: 同類、同包、子類可以使用,不同包不能。
(dafault)不寫: 同類、同包可以使用,子類、不同包不能。
private: 只有同類可以。
5.==和equals的區(qū)別
==: 基礎(chǔ)類型比較的值,引用類型比較的是地址值。
equals: 沒有重寫比較地址值是否相等,重寫比較的內(nèi)容是否相對(duì)。比如String類重寫equals,源碼首先比較是否都是String對(duì)象,然后再向下比較。
6.hashcode()值相同,equals就一定為true
不一定,因?yàn)?"重地"和"通話"的hashcode值就相同,但是equals()就為false。
但是equals()為true,那么hashcode一定相同。
7.為什么重寫equals(),就要重寫hashcode()?
保證同一對(duì)象,如果不重寫hashcode,可能會(huì)出現(xiàn)equals比較一樣,但是hashcode不一樣的情況。
8.short s = 1;s = s + 1;(程序1)和 short s = 1; s += 1;(程序2)是否都能正常運(yùn)行
程序1會(huì)編譯報(bào)錯(cuò),因?yàn)?s + 1的1是int類型,因?yàn)轭愋筒患嫒荨?qiáng)制轉(zhuǎn)換失敗。
程序2可以正常運(yùn)行,因?yàn)閖ava在復(fù)合賦值解釋是 E1 += E2,等價(jià)于 E1 = (T)(E1 + E2),T是E1的類型,因此s += 1等價(jià)于 s = (short)(s + 1),所以進(jìn)行了強(qiáng)制類型的轉(zhuǎn)換,所以可以正常編譯。
10.&和&&的區(qū)別
&&: 如果一邊為假,就不比較另一邊。具有短路行
&: 兩邊都為假,結(jié)果才為假,多用于位運(yùn)算。
11.String、StringBuffer、StringBuilder的區(qū)別
String: 適用于少量字符串。創(chuàng)建之后不可更改,對(duì)String的修改會(huì)生成新的String對(duì)象。
StringBuilder: 適用于大量字符串,線程不安全,性能更快。單線程使用
StringBuffer: 適用于大量字符串,線程安全。多線程使用,用synchronized關(guān)鍵字修飾。
12.String rap = new String(“ctrl”);創(chuàng)建了幾個(gè)對(duì)象?
一個(gè)或兩個(gè),如果常量池存在,那就在堆創(chuàng)建一個(gè)實(shí)例對(duì)象,否則常量池也需要?jiǎng)?chuàng)建一個(gè)。
13.什么是反射
在運(yùn)行過程中,對(duì)于任何一個(gè)類都能獲取它的屬性和方法,任何一個(gè)對(duì)象都能調(diào)用其方法,動(dòng)態(tài)獲取信息和動(dòng)態(tài)調(diào)用,就是反射。
14.淺拷貝和深拷貝的區(qū)別
淺拷貝: 基礎(chǔ)數(shù)據(jù)類型復(fù)制值,引用類型復(fù)制引用地址,修改一個(gè)對(duì)象的值,另一個(gè)對(duì)象也隨之改變。
深拷貝: 基礎(chǔ)數(shù)據(jù)類型復(fù)制值,引用類型在新的內(nèi)存空間復(fù)制值,新老對(duì)象不共享內(nèi)存,修改一個(gè)值,不影響另一個(gè)。
深拷貝相對(duì)淺拷貝速度慢,開銷大。
15.構(gòu)造器能被重寫嗎
不能,可以被重載。
16.并發(fā)和并行
并發(fā): 一個(gè)處理器同時(shí)處理多個(gè)任務(wù)。(一個(gè)人同時(shí)吃兩個(gè)蘋果)
并行: 多個(gè)處理器同時(shí)處理多個(gè)任務(wù)。(兩個(gè)人同時(shí)吃兩個(gè)蘋果)
1.List、Set、Map的區(qū)別
List集合有序、可重復(fù)的單例集合。
Set集合無序、不可重復(fù)的單例集合。
Map集合有序、k不可重復(fù),v可重復(fù)的雙例集合。
2.List、Set、Map常用集合有哪些?
List
vector: 底層是數(shù)組,方法加了synchronized來保證線程安全,所以效率較慢,使用ArrayList替代。
ArrayList: 線程不安全,底層是數(shù)組,因?yàn)閿?shù)組都是連續(xù)的地址,所以查詢比較快。增刪比較慢,增會(huì)生成一個(gè)新數(shù)組,把新增的元素和原有元素放到新數(shù)組中,刪除會(huì)導(dǎo)致元素移動(dòng),所以增刪速度較慢。
LinkedList: 線程不安全,底層是鏈表,因?yàn)榈刂凡皇沁B續(xù)的,都是一個(gè)節(jié)點(diǎn)和一個(gè)節(jié)點(diǎn)相連,每次查詢都得重頭開始查詢,所以查詢慢,增刪只是斷裂某個(gè)節(jié)點(diǎn)對(duì)整體影響不大,所以增刪速度較快。
Set
HashSet: 底層是哈希表(數(shù)組+鏈表或數(shù)組+紅黑樹),在鏈表長(zhǎng)度大于8時(shí)轉(zhuǎn)為紅黑樹,在紅黑樹節(jié)點(diǎn)小于6時(shí)轉(zhuǎn)為鏈表。其實(shí)就是實(shí)現(xiàn)了HashMap,值存入key,value是一個(gè)final修飾的對(duì)象。
TreeSet: 底層是紅黑樹結(jié)構(gòu),就是TreeMap實(shí)現(xiàn),可以實(shí)現(xiàn)有序的集合。String和Integer可以根據(jù)值進(jìn)行排序。如果是對(duì)象需要實(shí)現(xiàn)Comparator接口,重寫compareTo()方法制定比較規(guī)則。
LinkedHashSet: 實(shí)現(xiàn)了HashSet,多一條鏈表來記錄位置,所以是有序的。
Map<key,value>雙例結(jié)構(gòu)
TreeMap: 底層是紅黑樹,key可以按順序排列。
HashMap: 底層是哈希表,可以很快的儲(chǔ)存和檢索,無序,大量迭代情況不佳。
LinkedHashMap: 底層是哈希表+鏈表,有序,大量迭代情況佳。
3.ArrayList的初始容量是多少?擴(kuò)容機(jī)制是什么?擴(kuò)容過程是怎樣?
初始容量: 默認(rèn)10,也可以通過構(gòu)造方法傳入大小。
擴(kuò)容機(jī)制: 原數(shù)組長(zhǎng)度 + 原數(shù)組長(zhǎng)度/2(源碼中是原數(shù)組右移一位,也就相當(dāng)于除以2)
注意:擴(kuò)容后的ArrayList底層數(shù)組不是原來的數(shù)組。
擴(kuò)容過程: 因?yàn)锳rrayList底層是數(shù)組,所以它的擴(kuò)容機(jī)制和數(shù)組一樣,首先新建一個(gè)新數(shù)組,長(zhǎng)度是原數(shù)組的1.5倍,然后調(diào)用Arrays.copyof()復(fù)制原數(shù)組的值,然后賦值給新數(shù)組。
4.什么是哈希表
根據(jù)關(guān)鍵碼值(Key value)而直接進(jìn)行訪問的數(shù)據(jù)結(jié)構(gòu),在一個(gè)表中,通過H(key)計(jì)算出key在表中的位置,H(key)就是哈希函數(shù),表就是哈希表。
5.什么是哈希沖突
不同的key通過哈希函數(shù)計(jì)算出相同的儲(chǔ)存地址,這就是哈希沖突。
6.解決哈希沖突
(1)開放地址法
如果發(fā)生哈希沖突,就會(huì)以當(dāng)前地址為基準(zhǔn),再去尋找計(jì)算另一個(gè)位置,直到不發(fā)生哈希沖突。
尋找的方法有:① 線性探測(cè) 1,2,3,m
② 二次探測(cè) 1的平方,-1的平方,2的平方,-2的平方,k的平方,-k的平方,k<=m/2
③ 隨機(jī)探測(cè) 生成一個(gè)隨機(jī)數(shù),然后從隨機(jī)地址+隨機(jī)數(shù)++。
(2)鏈地址法
沖突的哈希值,連到到同一個(gè)鏈表上。
(3)再哈希法(再散列方法)
多個(gè)哈希函數(shù),發(fā)生沖突,就在用另一個(gè)算計(jì),直到?jīng)]有沖突。
(4)建立公共溢出區(qū)
哈希表分成基本表和溢出表,與基本表發(fā)生沖突的都填入溢出表。
7.HashMap的hash()算法,為什么不是h=key.hashcode(),而是key.hashcode()^ (h>>>16)
得到哈希值然后右移16位,然后進(jìn)行異或運(yùn)算,這樣使哈希值的低16位也具有了一部分高16位的特性,增加更多的變化性,減少了哈希沖突。
8.為什么HashMap的初始容量和擴(kuò)容都是2的次冪
因?yàn)橛?jì)算元素存儲(chǔ)的下標(biāo)是(n-1)&哈希值,數(shù)組初始容量-1,得到的二進(jìn)制都是1,這樣可以減少哈希沖突,可以更好的均勻插入。
9.HashMap如果指定了不是2的次冪的容量會(huì)發(fā)生什么?
會(huì)獲得一個(gè)大于指定的初始值的最接近2的次冪的值作為初始容量。
10.HashMap為什么線程不安全
jdk1.7中因?yàn)槭褂妙^插法,再擴(kuò)容的時(shí)候,可能會(huì)造成閉環(huán)和數(shù)據(jù)丟失。
jdk1.8中使用尾插法,不會(huì)出現(xiàn)閉環(huán)和數(shù)據(jù)丟失,但是在多線程下,會(huì)發(fā)生數(shù)據(jù)覆蓋。(put操作中,在putVal函數(shù)里) 值的覆蓋還有長(zhǎng)度的覆蓋。