亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

目錄
1、物件導(dǎo)向的三個(gè)基本特徵?
2、存取修飾符public,private,protected,以及不寫時(shí)的區(qū)別?
3、下面兩個(gè)程式碼區(qū)塊能正常編譯執(zhí)行嗎?
6、&和&&的區(qū)別?
7、String 是 Java 基本數(shù)據(jù)類型嗎?
8、String 類可以繼承嗎?
9、String和StringBuilder、StringBuffer的區(qū)別?
10、String s = new String("xyz") 創(chuàng)建了幾個(gè)字符串對(duì)象?
11、String s = "xyz" 和 String s = new String("xyz") 區(qū)別?
12、== 和 equals 的區(qū)別是什么?
13、兩個(gè)對(duì)象的 hashCode() 相同,則 equals() 也一定為 true,對(duì)嗎?
14、什么是反射
15、深拷貝和淺拷貝區(qū)別是什么?
16、并發(fā)和并行有什么區(qū)別?
17、構(gòu)造器是否可被 重寫?
18、當(dāng)一個(gè)對(duì)象被當(dāng)作參數(shù)傳遞到一個(gè)方法后,此方法可改變這個(gè)對(duì)象的屬性,并可返回變化后的結(jié)果,那么這里到底是值傳遞還是引用傳遞?
19、Java 靜態(tài)變量和成員變量的區(qū)別。
20、是否可以從一個(gè)靜態(tài)(static)方法內(nèi)部發(fā)出對(duì)非靜態(tài)(non-static)方法的調(diào)用?
21、初始化考察,請(qǐng)指出下面程序的運(yùn)行結(jié)果。
22、重載(Overload)和重寫(Override)的區(qū)別?
23、為什么不能根據(jù)返回類型來區(qū)分重載?
24、抽象類(abstract class)和接口(interface)有什么區(qū)別?
25、Error 和 Exception 有什么區(qū)別?
26、Java 中的 final 關(guān)鍵字有哪些用法?
27、闡述 final、finally、finalize 的區(qū)別。
30、try、catch、finally 考察3,請(qǐng)指出下面程序的運(yùn)行結(jié)果。
31、JDK1.8之後有哪些新功能?
32、wait() 和 sleep() 方法的區(qū)別
33、執(zhí)行緒的 sleep() 方法和 yield() 方法有什麼不同?
34、執(zhí)行緒的 join() 方法是乾啥用的?
35、寫多執(zhí)行緒程式有幾種實(shí)作方式?
36、Thread 呼叫start() 方法和呼叫run() 方法的區(qū)別
37、執(zhí)行緒的狀態(tài)流轉(zhuǎn)
38、synchronized 和 Lock 的區(qū)別
39、synchronized 各種加鎖場(chǎng)景的作用范圍
40、如何檢測(cè)死鎖?
41、怎么預(yù)防死鎖?
42、為什麼要使用執(zhí)行緒池?直接new個(gè)線程不是很舒服?
43、執(zhí)行緒池的核心屬性有哪些?
44、說下執(zhí)行緒池的運(yùn)作流程。
45、在執(zhí)行緒池有哪些拒絕策略?
46、List、Set、Map三者的差異?
47、ArrayList 和 LinkedList 的差異。
48、ArrayList 和 Vector 的區(qū)別。
49、介紹下HashMap 的底層資料結(jié)構(gòu)
50、為什麼要改成「陣列 鍊錶 紅黑樹」?
51、那在什麼時(shí)候用鍊錶?什麼時(shí)候用紅黑樹?
52、HashMap 的預(yù)設(shè)初始容量是多少? HashMap 的容量有什麼限制嗎?
53、HashMap 的插入流程是怎麼樣的?
54、HashMap 的擴(kuò)容(resize)流程是怎麼樣的?
55、除了 HashMap,還用過哪些 Map,使用時(shí)怎麼選擇?
56、HashMap?和Hashtable?的差異?
57、Java 記憶體結(jié)構(gòu)(執(zhí)行階段資料區(qū))
58、什么是雙親委派模型?
59、Java虛擬機(jī)中有哪些類加載器?
60、類加載的過程
61、介紹下垃圾收集機(jī)制(在什么時(shí)候,對(duì)什么,做了什么)?
62、GC Root有哪些?
63、垃圾收集有哪些演算法,各自的特色?
最後
首頁(yè) Java Java面試題 【吐血整理】2023年Java 基礎(chǔ)高頻面試題目及答案(收藏)

【吐血整理】2023年Java 基礎(chǔ)高頻面試題目及答案(收藏)

Jul 08, 2022 am 11:00 AM
java面試題

這篇文章為大家總結(jié)一些值得收藏的2023年精選Java基礎(chǔ)高頻面試題(附答案)。有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)大家有幫助。

【吐血整理】2023年Java 基礎(chǔ)高頻面試題目及答案(收藏)

1、物件導(dǎo)向的三個(gè)基本特徵?

物件導(dǎo)向的三個(gè)基本特徵是:封裝、繼承和多型。

繼承:讓某個(gè)類型的物件取得另一個(gè)類型的物件的屬性的方法。繼承就是子類別繼承父類別的特徵和行為,使得子類別物件(實(shí)例)具有父類別的實(shí)例域和方法,或子類別從父類別繼承方法,使得子類別具有父類別相同的行為。 (推薦教學(xué):java入門教學(xué)

封裝:隱藏部分物件的屬性和實(shí)作細(xì)節(jié),對(duì)資料的存取只能透過外公開的介面。透過這種方式,物件對(duì)內(nèi)部資料提供了不同程度的保護(hù),以防止程式中無關(guān)的部分意外的變更或錯(cuò)誤的使用了物件的私有部分。

多態(tài):對(duì)於同一個(gè)行為,不同的子類別物件有不同的表現(xiàn)形式。多態(tài)存在的3個(gè)條件:1)繼承;2)重寫;3)父類別引用指向子類別物件。

舉個(gè)簡(jiǎn)單的例子:英雄聯(lián)盟裡面我們按下Q 鍵這個(gè)動(dòng)作:

  • #對(duì)於亞索,就是斬鋼閃
  • 對(duì)於提莫,就是致盲吹箭
  • 對(duì)於劍聖,就是阿爾法突襲

同一個(gè)事件發(fā)生在不同的物件上會(huì)產(chǎn)生不同的結(jié)果。

我再舉一個(gè)簡(jiǎn)單的例子幫助大家理解,這個(gè)例子可能不是完全準(zhǔn)確,但是我認(rèn)為是有利於理解的。

public?class?Animal?{?//?動(dòng)物
????public?void?sleep()?{
????????System.out.println("躺著睡");
????}
}
class?Horse?extends?Animal?{?//?馬?是一種動(dòng)物
????public?void?sleep()?{
????????System.out.println("站著睡");
????}
}
class?Cat?extends?Animal?{?//?貓?是一種動(dòng)物
????private?int?age;
????public?int?getAge()?{
????????return?age?+?1;
????}
????@Override
????public?void?sleep()?{
????????System.out.println("四腳朝天的睡");
????}
}

在這個(gè)例子中:

House 和 Cat 都是 Animal,所以他們都繼承了 Animal,同時(shí)也從 Animal 繼承了 sleep 這個(gè)行為。

但針對(duì) sleep 這個(gè)行為,House 和 Cat 進(jìn)行了重寫,有了不同的表現(xiàn)形式(實(shí)作),這個(gè)我們稱為多態(tài)。

在 Cat 裡,將 age 屬性定義為 private,外界無法直接訪問,要獲取 Cat 的 age 資訊只能透過 getAge 方法,從而對(duì)外隱藏了 age 屬性,這個(gè)就叫做封裝。當(dāng)然,這邊 age 只是個(gè)例子,實(shí)際使用中可能是個(gè)複雜很多的物件。

2、存取修飾符public,private,protected,以及不寫時(shí)的區(qū)別?

3、下面兩個(gè)程式碼區(qū)塊能正常編譯執(zhí)行嗎?

//?代碼塊1
short?s1?=?1;?s1?=?s1?+?1;
//?代碼塊2
short?s1?=?1;?s1?+=?1;

程式碼區(qū)塊1編譯報(bào)錯(cuò),錯(cuò)誤原因是:不相容的型別: 從int轉(zhuǎn)換到short可能會(huì)有損失」。

程式碼區(qū)塊2正常編譯和執(zhí)行。

我們將程式碼區(qū)塊2進(jìn)行編譯,字節(jié)碼如下:

public?class?com.joonwhee.open.demo.Convert?{
??public?com.joonwhee.open.demo.Convert();
????Code:
???????0:?aload_0
???????1:?invokespecial?#1?//?Method?java/lang/Object."<init>":()V
???????4:?return

??public?static?void?main(java.lang.String[]);
????Code:
???????0:?iconst_1?//?將int類型值1入(操作數(shù))棧
???????1:?istore_1?//?將棧頂int類型值保存到局部變量1中
???????2:?iload_1?//?從局部變量1中裝載int類型值入棧
???????3:?iconst_1?//?將int類型值1入棧
???????4:?iadd?//?將棧頂兩int類型數(shù)相加,結(jié)果入棧
???????5:?i2s?//?將棧頂int類型值截?cái)喑蓅hort類型值,后帶符號(hào)擴(kuò)展成int類型值入棧。
???????6:?istore_1?//?將棧頂int類型值保存到局部變量1中
???????7:?return
}

可以看到字節(jié)碼中包含了i2s 指令,該指令用於將int 轉(zhuǎn)成short。i2s 是int to short 的縮寫。

其實(shí),s1 = 1 相當(dāng)於s1 = (short)(s1 1),有興趣的可以自己編譯下這兩行程式碼的字節(jié)碼,你會(huì)發(fā)現(xiàn)是一摸一樣的。

說好的Java 基礎(chǔ)題,怎麼又開始變態(tài)起來了???

##4、基礎(chǔ)考察,指出下題的輸出結(jié)果
public?static?void?main(String[]?args)?{
????Integer?a?=?128,?b?=?128,?c?=?127,?d?=?127;
????System.out.println(a?==?b);
????System.out.println(c?==?d);
}

答案是:false,true。

執(zhí)行Integer a = 128,相當(dāng)於執(zhí)行:Integer a = Integer.valueOf(128),基本類型自動(dòng)轉(zhuǎn)換為包裝類別的過程稱為自動(dòng)裝箱(autoboxing)。

public?static?Integer?valueOf(int?i)?{
????if?(i?>=?IntegerCache.low?&&?i?<= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

在Integer 中引入了IntegerCache 來快取一定範(fàn)圍的值,IntegerCache 預(yù)設(shè)範(fàn)圍為:-128~127。

本題的127 命中了?IntegerCache,所以c?和d?是相同對(duì)象,而128 則沒有命中,所以a?和b?是不同對(duì)象。

但是當(dāng)這個(gè)快取範(fàn)圍時(shí)可以修改的,可能有些人不知道??梢酝高^JVM啟動(dòng)參數(shù):-XX:AutoBoxCacheMax= 來修改上限值,如下圖所示:

5 、用最有效率的方法計(jì)算2乘以8?

2 << 3.

進(jìn)階:通常情況下,可以認(rèn)為位元運(yùn)算是效能最高的。但是,其實(shí)編譯器現(xiàn)在已經(jīng)“非常聰明了”,很多指令編譯器都能自己做優(yōu)化。所以在實(shí)際實(shí)用中,我們無需特意去追求實(shí)用位運(yùn)算,這樣不僅會(huì)導(dǎo)致代碼可讀性很差,而某些自作聰明的最佳化反而會(huì)誤導(dǎo)編譯器,使得編譯器無法進(jìn)行更好的最佳化。

這可能就是所謂的「豬隊(duì)友」吧。

6、&和&&的區(qū)別?

&&:邏輯與運(yùn)算符。當(dāng)運(yùn)算符左右兩邊的表達(dá)式都為 true,才返回 true。同時(shí)具有短路性,如果第一個(gè)表達(dá)式為 false,則直接返回 false。

&:邏輯與運(yùn)算符、按位與運(yùn)算符。

按位與運(yùn)算符:用于二進(jìn)制的計(jì)算,只有對(duì)應(yīng)的兩個(gè)二進(jìn)位均為1時(shí),結(jié)果位才為1 ,否則為0。

邏輯與運(yùn)算符:& 在用于邏輯與時(shí),和 && 的區(qū)別是不具有短路性。所在通常使用邏輯與運(yùn)算符都會(huì)使用 &&,而 & 更多的適用于位運(yùn)算。

7、String 是 Java 基本數(shù)據(jù)類型嗎?

答:不是。Java 中的基本數(shù)據(jù)類型只有8個(gè):byte、short、int、long、float、double、char、boolean;除了基本類型(primitive type),剩下的都是引用類型(reference type)。

基本數(shù)據(jù)類型:數(shù)據(jù)直接存儲(chǔ)在棧上

引用數(shù)據(jù)類型區(qū)別:數(shù)據(jù)存儲(chǔ)在堆上,棧上只存儲(chǔ)引用地址

8、String 類可以繼承嗎?

不行。String 類使用 final 修飾,無法被繼承。

9、String和StringBuilder、StringBuffer的區(qū)別?

String:String 的值被創(chuàng)建后不能修改,任何對(duì) String 的修改都會(huì)引發(fā)新的 String 對(duì)象的生成。

StringBuffer:跟 String 類似,但是值可以被修改,使用 synchronized 來保證線程安全。

StringBuilder:StringBuffer 的非線程安全版本,沒有使用 synchronized,具有更高的性能,推薦優(yōu)先使用。

10、String s = new String("xyz") 創(chuàng)建了幾個(gè)字符串對(duì)象?

一個(gè)或兩個(gè)。如果字符串常量池已經(jīng)有“xyz”,則是一個(gè);否則,兩個(gè)。

當(dāng)字符創(chuàng)常量池沒有 “xyz”,此時(shí)會(huì)創(chuàng)建如下兩個(gè)對(duì)象:

一個(gè)是字符串字面量 "xyz" 所對(duì)應(yīng)的、駐留(intern)在一個(gè)全局共享的字符串常量池中的實(shí)例,此時(shí)該實(shí)例也是在堆中,字符串常量池只放引用。

另一個(gè)是通過 new String() 創(chuàng)建并初始化的,內(nèi)容與"xyz"相同的實(shí)例,也是在堆中。

11、String s = "xyz" 和 String s = new String("xyz") 區(qū)別?

兩個(gè)語(yǔ)句都會(huì)先去字符串常量池中檢查是否已經(jīng)存在 “xyz”,如果有則直接使用,如果沒有則會(huì)在常量池中創(chuàng)建 “xyz” 對(duì)象。

另外,String s = new String("xyz") 還會(huì)通過 new String() 在堆里創(chuàng)建一個(gè)內(nèi)容與 "xyz" 相同的對(duì)象實(shí)例。

所以前者其實(shí)理解為被后者的所包含。

12、== 和 equals 的區(qū)別是什么?

==:運(yùn)算符,用于比較基礎(chǔ)類型變量和引用類型變量。

對(duì)于基礎(chǔ)類型變量,比較的變量保存的值是否相同,類型不一定要相同。

short s1 = 1; long l1 = 1;
// 結(jié)果:true。類型不同,但是值相同
System.out.println(s1 == l1);

對(duì)于引用類型變量,比較的是兩個(gè)對(duì)象的地址是否相同。

Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
// 結(jié)果:false。通過new創(chuàng)建,在內(nèi)存中指向兩個(gè)不同的對(duì)象
System.out.println(i1 == i2);

equals:Object 類中定義的方法,通常用于比較兩個(gè)對(duì)象的值是否相等。

equals 在 Object 方法中其實(shí)等同于 ==,但是在實(shí)際的使用中,equals 通常被重寫用于比較兩個(gè)對(duì)象的值是否相同。

Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
// 結(jié)果:true。兩個(gè)不同的對(duì)象,但是具有相同的值
System.out.println(i1.equals(i2));

// Integer的equals重寫方法
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        // 比較對(duì)象中保存的值是否相同
        return value == ((Integer)obj).intValue();
    }
    return false;
}

13、兩個(gè)對(duì)象的 hashCode() 相同,則 equals() 也一定為 true,對(duì)嗎?

不對(duì)。hashCode() 和 equals() 之間的關(guān)系如下:

當(dāng)有 a.equals(b) == true 時(shí),則 a.hashCode() == b.hashCode() 必然成立,

反過來,當(dāng) a.hashCode() == b.hashCode() 時(shí),a.equals(b) 不一定為 true。

14、什么是反射

反射是指在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類都能夠知道這個(gè)類所有的屬性和方法;并且對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱為反射機(jī)制。

15、深拷貝和淺拷貝區(qū)別是什么?

數(shù)據(jù)分為基本數(shù)據(jù)類型和引用數(shù)據(jù)類型?;緮?shù)據(jù)類型:數(shù)據(jù)直接存儲(chǔ)在棧中;引用數(shù)據(jù)類型:存儲(chǔ)在棧中的是對(duì)象的引用地址,真實(shí)的對(duì)象數(shù)據(jù)存放在堆內(nèi)存里。

淺拷貝:對(duì)于基礎(chǔ)數(shù)據(jù)類型:直接復(fù)制數(shù)據(jù)值;對(duì)于引用數(shù)據(jù)類型:只是復(fù)制了對(duì)象的引用地址,新舊對(duì)象指向同一個(gè)內(nèi)存地址,修改其中一個(gè)對(duì)象的值,另一個(gè)對(duì)象的值隨之改變。

深拷貝:對(duì)于基礎(chǔ)數(shù)據(jù)類型:直接復(fù)制數(shù)據(jù)值;對(duì)于引用數(shù)據(jù)類型:開辟新的內(nèi)存空間,在新的內(nèi)存空間里復(fù)制一個(gè)一模一樣的對(duì)象,新老對(duì)象不共享內(nèi)存,修改其中一個(gè)對(duì)象的值,不會(huì)影響另一個(gè)對(duì)象。

深拷貝相比于淺拷貝速度較慢并且花銷較大。

16、并發(fā)和并行有什么區(qū)別?

并發(fā):兩個(gè)或多個(gè)事件在同一時(shí)間間隔發(fā)生。

并行:兩個(gè)或者多個(gè)事件在同一時(shí)刻發(fā)生。

并行是真正意義上,同一時(shí)刻做多件事情,而并發(fā)在同一時(shí)刻只會(huì)做一件事件,只是可以將時(shí)間切碎,交替做多件事情。

網(wǎng)上有個(gè)例子挺形象的:

你吃飯吃到一半,電話來了,你一直到吃完了以后才去接,這就說明你不支持并發(fā)也不支持并行。

你吃飯吃到一半,電話來了,你停了下來接了電話,接完后繼續(xù)吃飯,這說明你支持并發(fā)。

你吃飯吃到一半,電話來了,你一邊打電話一邊吃飯,這說明你支持并行。

17、構(gòu)造器是否可被 重寫?

Constructor 不能被 override(重寫),但是可以 overload(重載),所以你可以看到?個(gè)類中有多個(gè)構(gòu)造函數(shù)的情況。

18、當(dāng)一個(gè)對(duì)象被當(dāng)作參數(shù)傳遞到一個(gè)方法后,此方法可改變這個(gè)對(duì)象的屬性,并可返回變化后的結(jié)果,那么這里到底是值傳遞還是引用傳遞?

值傳遞。Java 中只有值傳遞,對(duì)于對(duì)象參數(shù),值的內(nèi)容是對(duì)象的引用。

19、Java 靜態(tài)變量和成員變量的區(qū)別。

public class Demo {
    /**
     * 靜態(tài)變量:又稱類變量,static修飾
     */
    public static String STATIC_VARIABLE = "靜態(tài)變量";
    /**
     * 實(shí)例變量:又稱成員變量,沒有static修飾
     */
    public String INSTANCE_VARIABLE = "實(shí)例變量";
}

成員變量存在于堆內(nèi)存中。靜態(tài)變量存在于方法區(qū)中。

成員變量與對(duì)象共存亡,隨著對(duì)象創(chuàng)建而存在,隨著對(duì)象被回收而釋放。靜態(tài)變量與類共存亡,隨著類的加載而存在,隨著類的消失而消失。

成員變量所屬于對(duì)象,所以也稱為實(shí)例變量。靜態(tài)變量所屬于類,所以也稱為類變量。

成員變量只能被對(duì)象所調(diào)用 。靜態(tài)變量可以被對(duì)象調(diào)用,也可以被類名調(diào)用。

20、是否可以從一個(gè)靜態(tài)(static)方法內(nèi)部發(fā)出對(duì)非靜態(tài)(non-static)方法的調(diào)用?

區(qū)分兩種情況,發(fā)出調(diào)用時(shí)是否顯示創(chuàng)建了對(duì)象實(shí)例。

1)沒有顯示創(chuàng)建對(duì)象實(shí)例:不可以發(fā)起調(diào)用,非靜態(tài)方法只能被對(duì)象所調(diào)用,靜態(tài)方法可以通過對(duì)象調(diào)用,也可以通過類名調(diào)用,所以靜態(tài)方法被調(diào)用時(shí),可能還沒有創(chuàng)建任何實(shí)例對(duì)象。因此通過靜態(tài)方法內(nèi)部發(fā)出對(duì)非靜態(tài)方法的調(diào)用,此時(shí)可能無法知道非靜態(tài)方法屬于哪個(gè)對(duì)象。

public class Demo {
    public static void staticMethod() {
        // 直接調(diào)用非靜態(tài)方法:編譯報(bào)錯(cuò)
        instanceMethod();
    }
    public void instanceMethod() {
        System.out.println("非靜態(tài)方法");
    }
}

2)顯示創(chuàng)建對(duì)象實(shí)例:可以發(fā)起調(diào)用,在靜態(tài)方法中顯示的創(chuàng)建對(duì)象實(shí)例,則可以正常的調(diào)用。

public class Demo {
    public static void staticMethod() {
        // 先創(chuàng)建實(shí)例對(duì)象,再調(diào)用非靜態(tài)方法:成功執(zhí)行
        Demo demo = new Demo();
        demo.instanceMethod();
    }
    public void instanceMethod() {
        System.out.println("非靜態(tài)方法");
    }
}

21、初始化考察,請(qǐng)指出下面程序的運(yùn)行結(jié)果。

public class InitialTest {
    public static void main(String[] args) {
        A ab = new B();
        ab = new B();
    }
}
class A {
    static { // 父類靜態(tài)代碼塊
        System.out.print("A");
    }
    public A() { // 父類構(gòu)造器
        System.out.print("a");
    }
}
class B extends A {
    static { // 子類靜態(tài)代碼塊
        System.out.print("B");
    }
    public B() { // 子類構(gòu)造器
        System.out.print("b");
    }
}

執(zhí)行結(jié)果:ABabab,兩個(gè)考察點(diǎn):

1)靜態(tài)變量只會(huì)初始化(執(zhí)行)一次。

2)當(dāng)有父類時(shí),完整的初始化順序?yàn)椋焊割愳o態(tài)變量(靜態(tài)代碼塊)->子類靜態(tài)變量(靜態(tài)代碼塊)->父類非靜態(tài)變量(非靜態(tài)代碼塊)->父類構(gòu)造器 ->子類非靜態(tài)變量(非靜態(tài)代碼塊)->子類構(gòu)造器 。

關(guān)于初始化,這題算入門題,我之前還寫過一道有(fei)點(diǎn)(chang)意(bian)思(tai)的進(jìn)階題目,有興趣的可以看看:一道有意思的“初始化”面試題

22、重載(Overload)和重寫(Override)的區(qū)別?

方法的重載和重寫都是實(shí)現(xiàn)多態(tài)的方式,區(qū)別在于前者實(shí)現(xiàn)的是編譯時(shí)的多態(tài)性,而后者實(shí)現(xiàn)的是運(yùn)行時(shí)的多態(tài)性。

重載:一個(gè)類中有多個(gè)同名的方法,但是具有有不同的參數(shù)列表(參數(shù)類型不同、參數(shù)個(gè)數(shù)不同或者二者都不同)。

重寫:發(fā)生在子類與父類之間,子類對(duì)父類的方法進(jìn)行重寫,參數(shù)都不能改變,返回值類型可以不相同,但是必須是父類返回值的派生類。即外殼不變,核心重寫!重寫的好處在于子類可以根據(jù)需要,定義特定于自己的行為。

23、為什么不能根據(jù)返回類型來區(qū)分重載?

如果我們有兩個(gè)方法如下,當(dāng)我們調(diào)用:test(1) 時(shí),編譯器無法確認(rèn)要調(diào)用的是哪個(gè)。

//?方法1
int?test(int?a);
//?方法2
long?test(int?a);

方法的返回值只是作為方法運(yùn)行之后的一個(gè)“狀態(tài)”,但是并不是所有調(diào)用都關(guān)注返回值,所以不能將返回值作為重載的唯一區(qū)分條件。

24、抽象類(abstract class)和接口(interface)有什么區(qū)別?

抽象類只能單繼承,接口可以多實(shí)現(xiàn)。

抽象類可以有構(gòu)造方法,接口中不能有構(gòu)造方法。

抽象類中可以有成員變量,接口中沒有成員變量,只能有常量(默認(rèn)就是 public static final)

抽象類中可以包含非抽象的方法,在 Java 7 之前接口中的所有方法都是抽象的,在 Java 8 之后,接口支持非抽象方法:default 方法、靜態(tài)方法等。Java 9 支持私有方法、私有靜態(tài)方法。

抽象類中的方法類型可以是任意修飾符,Java 8 之前接口中的方法只能是 public 類型,Java 9 支持 private 類型。

設(shè)計(jì)思想的區(qū)別:

接口是自上而下的抽象過程,接口規(guī)范了某些行為,是對(duì)某一行為的抽象。我需要這個(gè)行為,我就去實(shí)現(xiàn)某個(gè)接口,但是具體這個(gè)行為怎么實(shí)現(xiàn),完全由自己決定。

抽象類是自下而上的抽象過程,抽象類提供了通用實(shí)現(xiàn),是對(duì)某一類事物的抽象。我們?cè)趯憣?shí)現(xiàn)類的時(shí)候,發(fā)現(xiàn)某些實(shí)現(xiàn)類具有幾乎相同的實(shí)現(xiàn),因此我們將這些相同的實(shí)現(xiàn)抽取出來成為抽象類,然后如果有一些差異點(diǎn),則可以提供抽象方法來支持自定義實(shí)現(xiàn)。

我在網(wǎng)上看到有個(gè)說法,挺形象的:

普通類像親爹 ,他有啥都是你的。

抽象類像叔伯,有一部分會(huì)給你,還能指導(dǎo)你做事的方法。

接口像干爹,可以給你指引方法,但是做成啥樣得你自己努力實(shí)現(xiàn)。

25、Error 和 Exception 有什么區(qū)別?

Error 和 Exception 都是 Throwable 的子類,用于表示程序出現(xiàn)了不正常的情況。區(qū)別在于:

Error 表示系統(tǒng)級(jí)的錯(cuò)誤和程序不必處理的異常,是恢復(fù)不是不可能但很困難的情況下的一種嚴(yán)重問題,比如內(nèi)存溢出,不可能指望程序能處理這樣的情況。

Exception 表示需要捕捉或者需要程序進(jìn)行處理的異常,是一種設(shè)計(jì)或?qū)崿F(xiàn)問題,也就是說,它表示如果程序運(yùn)行正常,從不會(huì)發(fā)生的情況。

26、Java 中的 final 關(guān)鍵字有哪些用法?

修飾類:該類不能再派生出新的子類,不能作為父類被繼承。因此,一個(gè)類不能同時(shí)被聲明為abstract 和 final。

修飾方法:該方法不能被子類重寫。

修飾變量:該變量必須在聲明時(shí)給定初值,而在以后只能讀取,不可修改。 如果變量是對(duì)象,則指的是引用不可修改,但是對(duì)象的屬性還是可以修改的。

public?class?FinalDemo?{
????//?不可再修改該變量的值
????public?static?final?int?FINAL_VARIABLE?=?0;
????//?不可再修改該變量的引用,但是可以直接修改屬性值
????public?static?final?User?USER?=?new?User();
????public?static?void?main(String[]?args)?{
????????//?輸出:User(id=0,?name=null,?age=0)
????????System.out.println(USER);
????????//?直接修改屬性值
????????USER.setName("test");
????????//?輸出:User(id=0,?name=test,?age=0)
????????System.out.println(USER);
????}
}

27、闡述 final、finally、finalize 的區(qū)別。

其實(shí)是三個(gè)完全不相關(guān)的東西,只是長(zhǎng)的有點(diǎn)像。。

final 如上所示。

finally:finally 是對(duì) Java 異常處理機(jī)制的最佳補(bǔ)充,通常配合 try、catch 使用,用于存放那些無論是否出現(xiàn)異常都一定會(huì)執(zhí)行的代碼。在實(shí)際使用中,通常用于釋放鎖、數(shù)據(jù)庫(kù)連接等資源,把資源釋放方法放到 finally 中,可以大大降低程序出錯(cuò)的幾率。

finalize:Object 中的方法,在垃圾收集器將對(duì)象從內(nèi)存中清除出去之前做必要的清理工作。finalize()方法僅作為了解即可,在 Java 9 中該方法已經(jīng)被標(biāo)記為廢棄,并添加新的 java.lang.ref.Cleaner,提供了更靈活和有效的方法來釋放資源。這也側(cè)面說明了,這個(gè)方法的設(shè)計(jì)是失敗的,因此更加不能去使用它。

28、try、catch、finally 考察,請(qǐng)指出下面程序的運(yùn)行結(jié)果。

public?class?TryDemo?{
????public?static?void?main(String[]?args)?{
????????System.out.println(test());
????}
????public?static?int?test()?{
????????try?{
????????????return?1;
????????}?catch?(Exception?e)?{
????????????return?2;
????????}?finally?{
????????????System.out.print("3");
????????}
????}
}

執(zhí)行結(jié)果:31。

相信很多同學(xué)應(yīng)該都做對(duì)了,try、catch。finally 的基礎(chǔ)用法,在 return 前會(huì)先執(zhí)行 finally 語(yǔ)句塊,所以是先輸出 finally 里的 3,再輸出 return 的 1。

29、try、catch、finally 考察2,請(qǐng)指出下面程序的運(yùn)行結(jié)果。

public?class?TryDemo?{
????public?static?void?main(String[]?args)?{
????????System.out.println(test1());
????}
????public?static?int?test1()?{
????????try?{
????????????return?2;
????????}?finally?{
????????????return?3;
????????}
????}
}

執(zhí)行結(jié)果:3。

這題有點(diǎn)陷阱,但也不難,try 返回前先執(zhí)行 finally,結(jié)果 finally 里不按套路出牌,直接 return 了,自然也就走不到 try 里面的 return 了。

finally 里面使用 return 僅存在于面試題中,實(shí)際開發(fā)中千萬不要這么用。

30、try、catch、finally 考察3,請(qǐng)指出下面程序的運(yùn)行結(jié)果。

public?class?TryDemo?{
????public?static?void?main(String[]?args)?{
????????System.out.println(test1());
????}
????public?static?int?test1()?{
????????int?i?=?0;
????????try?{
????????????i?=?2;
????????????return?i;
????????}?finally?{
????????????i?=?3;
????????}
????}
}

執(zhí)行結(jié)果:2。

這邊估計(jì)有不少同學(xué)會(huì)以為結(jié)果應(yīng)該是 3,因?yàn)槲覀冎涝?return 前會(huì)執(zhí)行 finally,而 i 在 finally 中被修改為 3 了,那最終返回 i 不是應(yīng)該為 3 嗎?確實(shí)很容易這么想,我最初也是這么想的,當(dāng)初的自己還是太年輕了啊。

這邊的根本原因是,在執(zhí)行 finally 之前,JVM 會(huì)先將 i 的結(jié)果暫存起來,然后 finally 執(zhí)行完畢后,會(huì)返回之前暫存的結(jié)果,而不是返回 i,所以即使這邊 i 已經(jīng)被修改為 3,最終返回的還是之前暫存起來的結(jié)果 2。

這邊其實(shí)根據(jù)字節(jié)碼可以很容易看出來,在進(jìn)入finally 之前,JVM 會(huì)使用iload、istore 兩個(gè)指令,將結(jié)果暫存,在最終返回時(shí)在透過iload、ireturn 指令返回暫存的結(jié)果。

為了避免氣氛再次變態(tài)起來,我這邊就不貼具體的字節(jié)碼程式了,有興趣的同學(xué)可以自己編譯查看下。

31、JDK1.8之後有哪些新功能?

介面預(yù)設(shè)方法:Java 8允許我們?yōu)榻槊嫣砑右粋€(gè)非抽象的方法實(shí)現(xiàn),只需要使用default關(guān)鍵字即可

Lambda 表達(dá)式和函數(shù)式介面:Lambda表達(dá)式本質(zhì)上是一段匿名內(nèi)部類,也可以是一段可以傳遞的程式碼。 Lambda 允許把函數(shù)作為一個(gè)方法的參數(shù)(函數(shù)作為參數(shù)傳遞到方法中),使用Lambda 表達(dá)式使程式碼更加簡(jiǎn)潔,但也不要濫用,否則會(huì)有可讀性等問題,《Effective Java》作者Josh Bloch 建議使用Lambda 表達(dá)式最好不要超過3行。

Stream API:用函數(shù)式程式設(shè)計(jì)方式在集合類別上進(jìn)行複雜運(yùn)算的工具,配合Lambda表達(dá)式可以方便的對(duì)集合進(jìn)行處理。 Java8 中處理集合的關(guān)鍵抽象概念,它可以指定你希望對(duì)集合進(jìn)行的操作,可以執(zhí)行非常複雜的查找、過濾和映射資料等操作。使用Stream API 對(duì)集合資料進(jìn)行操作,就類似於使用 SQL 執(zhí)行的資料庫(kù)查詢。也可以使用 Stream API 來並行執(zhí)行操作。簡(jiǎn)而言之,Stream API 提供了一種高效且易於使用的處理資料的方式。

方法參考:方法參考提供了一個(gè)非常有用的語(yǔ)法,可以直接引用已有Java類別或物件(實(shí)例)的方法或建構(gòu)器。與lambda聯(lián)合使用,方法引用可以使語(yǔ)言的構(gòu)造更緊湊簡(jiǎn)潔,減少冗餘程式碼。

日期時(shí)間API:Java 8 引進(jìn)了新的日期時(shí)間API改進(jìn)了日期時(shí)間的管理。

Optional 類別:著名的 NullPointerException?是造成系統(tǒng)失敗最常見的原因。很久以前 Google Guava 專案引入了 Optional 作為解決空指標(biāo)異常的一種方式,不贊成程式碼被 null 檢查的程式碼污染,期望程式設(shè)計(jì)師寫整潔的程式碼。受Google Guava的鼓勵(lì),Optional?現(xiàn)在是Java 8庫(kù)的一部分。

新工具:新的編譯工具,如:Nashorn引擎 jjs、 類別依賴分析器 jdeps。

32、wait() 和 sleep() 方法的區(qū)別

來源不同:sleep() 來自 Thread 類,wait() 來自 Object 類別。

對(duì)於同步鎖定的影響不同:sleep() 不會(huì)該資料表同步鎖定的行為,如果目前執(zhí)行緒持有同步鎖定,那麼 sleep 是不會(huì)讓執(zhí)行緒釋放同步鎖定的。 wait() 會(huì)釋放同步鎖,讓其他執(zhí)行緒進(jìn)入 synchronized 程式碼區(qū)塊執(zhí)行。

使用範(fàn)圍不同:sleep() 可以在任何地方使用。 wait() 只能在同步控制方法或同步控制區(qū)塊裡面使用,否則會(huì)拋 IllegalMonitorStateException。

恢復(fù)方式不同:兩者會(huì)暫停當(dāng)前線程,但是在恢復(fù)上不太一樣。 sleep() 在時(shí)間到了之後會(huì)重新恢復(fù);wait() 則需要其他執(zhí)行緒呼叫相同物件的 notify()/nofityAll() 才能重新復(fù)原。

33、執(zhí)行緒的 sleep() 方法和 yield() 方法有什麼不同?

執(zhí)行緒執(zhí)行 sleep() 方法後進(jìn)入逾時(shí)等待(TIMED_WAITING)狀態(tài),而執(zhí)行 yield() 方法後進(jìn)入就緒(READY)狀態(tài)。

sleep() 方法給其他執(zhí)行緒運(yùn)行機(jī)會(huì)時(shí)不考慮執(zhí)行緒的優(yōu)先權(quán),因此會(huì)給低優(yōu)先權(quán)的執(zhí)行緒運(yùn)行的機(jī)會(huì);yield() 方法只會(huì)給相同優(yōu)先權(quán)或更高優(yōu)先權(quán)的線程以運(yùn)行的機(jī)會(huì)。

34、執(zhí)行緒的 join() 方法是乾啥用的?

用於等待目前執(zhí)行緒終止。如果一個(gè)執(zhí)行緒A執(zhí)行了 threadB.join() 語(yǔ)句,其意義是:當(dāng)前執(zhí)行緒A等待 threadB 執(zhí)行緒終止之後才從 threadB.join() 回傳繼續(xù)往下執(zhí)行自己的程式碼。

35、寫多執(zhí)行緒程式有幾種實(shí)作方式?

通常來說,可以認(rèn)為有三種方式:1)繼承 Thread 類別;2)實(shí)作 Runnable 介面;3)實(shí)作 Callable 介面。

其中,Thread 其實(shí)也是實(shí)作了 Runable 介面。 Runnable 和?Callable 的主要差異在於是否有回傳值。

36、Thread 呼叫start() 方法和呼叫run() 方法的區(qū)別

run():普通的方法調(diào)用,在主執(zhí)行緒中執(zhí)行,不會(huì)新建一個(gè)執(zhí)行緒來執(zhí)行。

start():新啟動(dòng)一個(gè)線程,這時(shí)此線程處?kù)毒途w(可運(yùn)行)狀態(tài),並沒有運(yùn)行,一旦得到 CPU 時(shí)間片,就開始執(zhí)行 run() 方法。

37、執(zhí)行緒的狀態(tài)流轉(zhuǎn)

#一個(gè)執(zhí)行緒可以處?kù)断铝袪顟B(tài)之一:

NEW:新建但是尚未啟動(dòng)的線程處于此狀態(tài),沒有調(diào)用 start() 方法。

RUNNABLE:包含就緒(READY)和運(yùn)行中(RUNNING)兩種狀態(tài)。線程調(diào)用 start() 方法會(huì)會(huì)進(jìn)入就緒(READY)狀態(tài),等待獲取 CPU 時(shí)間片。如果成功獲取到 CPU 時(shí)間片,則會(huì)進(jìn)入運(yùn)行中(RUNNING)狀態(tài)。

BLOCKED:線程在進(jìn)入同步方法/同步塊(synchronized)時(shí)被阻塞,等待同步鎖的線程處于此狀態(tài)。

WAITING:無限期等待另一個(gè)線程執(zhí)行特定操作的線程處于此狀態(tài),需要被顯示的喚醒,否則會(huì)一直等待下去。例如對(duì)于 Object.wait(),需要等待另一個(gè)線程執(zhí)行 Object.notify() 或 Object.notifyAll();對(duì)于 Thread.join(),則需要等待指定的線程終止。

TIMED_WAITING:在指定的時(shí)間內(nèi)等待另一個(gè)線程執(zhí)行某項(xiàng)操作的線程處于此狀態(tài)。跟 WAITING 類似,區(qū)別在于該狀態(tài)有超時(shí)時(shí)間參數(shù),在超時(shí)時(shí)間到了后會(huì)自動(dòng)喚醒,避免了無期限的等待。

TERMINATED:執(zhí)行完畢已經(jīng)退出的線程處于此狀態(tài)。

線程在給定的時(shí)間點(diǎn)只能處于一種狀態(tài)。這些狀態(tài)是虛擬機(jī)狀態(tài),不反映任何操作系統(tǒng)線程狀態(tài)。

38、synchronized 和 Lock 的區(qū)別

1)Lock 是一個(gè)接口;synchronized 是 Java 中的關(guān)鍵字,synchronized 是內(nèi)置的語(yǔ)言實(shí)現(xiàn);

2)Lock 在發(fā)生異常時(shí),如果沒有主動(dòng)通過 unLock() 去釋放鎖,很可能會(huì)造成死鎖現(xiàn)象,因此使用 Lock 時(shí)需要在 finally 塊中釋放鎖;synchronized 不需要手動(dòng)獲取鎖和釋放鎖,在發(fā)生異常時(shí),會(huì)自動(dòng)釋放鎖,因此不會(huì)導(dǎo)致死鎖現(xiàn)象發(fā)生;

3)Lock 的使用更加靈活,可以有響應(yīng)中斷、有超時(shí)時(shí)間等;而 synchronized 卻不行,使用 synchronized 時(shí),等待的線程會(huì)一直等待下去,直到獲取到鎖;

4)在性能上,隨著近些年 synchronized 的不斷優(yōu)化,Lock 和 synchronized 在性能上已經(jīng)沒有很明顯的差距了,所以性能不應(yīng)該成為我們選擇兩者的主要原因。官方推薦盡量使用 synchronized,除非 synchronized 無法滿足需求時(shí),則可以使用 Lock。

39、synchronized 各種加鎖場(chǎng)景的作用范圍

1.作用于非靜態(tài)方法,鎖住的是對(duì)象實(shí)例(this),每一個(gè)對(duì)象實(shí)例有一個(gè)鎖。

public?synchronized?void?method()?{}

2.作用于靜態(tài)方法,鎖住的是類的Class對(duì)象,因?yàn)镃lass的相關(guān)數(shù)據(jù)存儲(chǔ)在永久代元空間,元空間是全局共享的,因此靜態(tài)方法鎖相當(dāng)于類的一個(gè)全局鎖,會(huì)鎖所有調(diào)用該方法的線程。

public?static?synchronized?void?method()?{}

3.作用于 Lock.class,鎖住的是 Lock 的Class對(duì)象,也是全局只有一個(gè)。

synchronized?(Lock.class)?{}

4.作用于 this,鎖住的是對(duì)象實(shí)例,每一個(gè)對(duì)象實(shí)例有一個(gè)鎖。

synchronized?(this)?{}

5.作用于靜態(tài)成員變量,鎖住的是該靜態(tài)成員變量對(duì)象,由于是靜態(tài)變量,因此全局只有一個(gè)。

public?static?Object?monitor?=?new?Object();?synchronized?(monitor)?{}

40、如何檢測(cè)死鎖?

死鎖的四個(gè)必要條件:

1)互斥條件:進(jìn)程對(duì)所分配到的資源進(jìn)行排他性控制,即在一段時(shí)間內(nèi)某資源僅為一個(gè)進(jìn)程所占有。此時(shí)若有其他進(jìn)程請(qǐng)求該資源,則請(qǐng)求進(jìn)程只能等待。

2)請(qǐng)求和保持條件:進(jìn)程已經(jīng)獲得了至少一個(gè)資源,但又對(duì)其他資源發(fā)出請(qǐng)求,而該資源已被其他進(jìn)程占有,此時(shí)該進(jìn)程的請(qǐng)求被阻塞,但又對(duì)自己獲得的資源保持不放。

3)不可剝奪條件:進(jìn)程已獲得的資源在未使用完畢之前,不可被其他進(jìn)程強(qiáng)行剝奪,只能由自己釋放。

4)環(huán)路等待條件:存在一種進(jìn)程資源的循環(huán)等待鏈,鏈中每一個(gè)進(jìn)程已獲得的資源同時(shí)被 鏈中下一個(gè)進(jìn)程所請(qǐng)求。即存在一個(gè)處于等待狀態(tài)的進(jìn)程集合{Pl, P2, …, pn},其中 Pi 等待的資源被 P(i+1) 占有(i=0, 1, …, n-1),Pn 等待的資源被 P0占 有,如下圖所示。

41、怎么預(yù)防死鎖?

預(yù)防死鎖的方式就是打破四個(gè)必要條件中的任意一個(gè)即可。

1)打破互斥條件:在系統(tǒng)里取消互斥。若資源不被一個(gè)進(jìn)程獨(dú)占使用,那么死鎖是肯定不會(huì)發(fā)生的。但一般來說在所列的四個(gè)條件中,“互斥”條件是無法破壞的。因此,在死鎖預(yù)防里主要是破壞其他幾個(gè)必要條件,而不去涉及破壞“互斥”條件。。

2)打破請(qǐng)求和保持條件:1)采用資源預(yù)先分配策略,即進(jìn)程運(yùn)行前申請(qǐng)全部資源,滿足則運(yùn)行,不然就等待。 2)每個(gè)進(jìn)程提出新的資源申請(qǐng)前,必須先釋放它先前所占有的資源。

3)打破不可剝奪條件:當(dāng)進(jìn)程佔(zhàn)有某些資源後又進(jìn)一步申請(qǐng)其他資源而無法滿足,則該進(jìn)程必須釋放它原來佔(zhàn)有的資源。

4)打破環(huán)路等待條件:實(shí)現(xiàn)資源有序分配策略,將系統(tǒng)的所有資源統(tǒng)一編號(hào),所有程序只能以序號(hào)遞增的形式申請(qǐng)資源。

42、為什麼要使用執(zhí)行緒池?直接new個(gè)線程不是很舒服?

如果我們?cè)诜椒ㄖ兄苯觧ew一個(gè)線程來處理,當(dāng)這個(gè)方法被呼叫頻繁時(shí)就會(huì)創(chuàng)建很多線程,不僅會(huì)消耗系統(tǒng)資源,還會(huì)降低系統(tǒng)的穩(wěn)定性,一不小心把系統(tǒng)搞崩了,就可以直接去財(cái)務(wù)結(jié)帳了。

如果我們合理的使用執(zhí)行緒池,則可以避免把系統(tǒng)搞崩的困境??偟脕碚f,使用執(zhí)行緒池可以帶來以下幾個(gè)好處:

  • 降低資源消耗。透過重複利用已建立的線程,降低線程創(chuàng)建和銷毀造成的消耗。
  • 提高反應(yīng)速度。當(dāng)任務(wù)到達(dá)時(shí),任務(wù)可以不需要等到執(zhí)行緒建立就能立即執(zhí)行。
  • 增加執(zhí)行緒的可管理型。執(zhí)行緒是稀缺資源,使用執(zhí)行緒池可以進(jìn)行統(tǒng)一分配,調(diào)優(yōu)和監(jiān)控。

43、執(zhí)行緒池的核心屬性有哪些?

threadFactory(執(zhí)行緒工廠):用於建立工作執(zhí)行緒的工廠。

corePoolSize(核心執(zhí)行緒數(shù)):當(dāng)執(zhí)行緒池執(zhí)行的執(zhí)行緒少於 corePoolSize 時(shí),將建立一個(gè)新執(zhí)行緒來處理請(qǐng)求,即使其他工作執(zhí)行緒處?kù)犊臻f狀態(tài)。

workQueue(佇列):用於保留任務(wù)並移交給工作執(zhí)行緒的阻塞佇列。

maximumPoolSize(最大執(zhí)行緒數(shù)):執(zhí)行緒池允許開啟的最大執(zhí)行緒數(shù)。

handler(拒絕策略):在執(zhí)行緒池中新增任務(wù)時(shí),將在下面兩種情況觸發(fā)拒絕策略:1)執(zhí)行緒池運(yùn)行狀態(tài)不是RUNNING;2)執(zhí)行緒池已經(jīng)達(dá)到最大執(zhí)行緒數(shù),並且阻塞隊(duì)列已滿時(shí)。

keepAliveTime(保持存活時(shí)間):如果執(zhí)行緒池目前執(zhí)行緒數(shù)超過 corePoolSize,則多餘的執(zhí)行緒空閒時(shí)間超過 keepAliveTime 時(shí)會(huì)被終止。

44、說下執(zhí)行緒池的運(yùn)作流程。

45、在執(zhí)行緒池有哪些拒絕策略?

AbortPolicy:中止策略。預(yù)設(shè)的拒絕策略,直接拋出 RejectedExecutionException。呼叫者可以捕獲這個(gè)異常,然後根據(jù)需求編寫自己的處理程式碼。

DiscardPolicy:拋棄策略。什麼都不做,直接拋棄被拒絕的任務(wù)。

DiscardOldestPolicy:拋棄最老策略。拋棄阻塞佇列中最老的任務(wù),相當(dāng)於就是佇列中下一個(gè)將要執(zhí)行的任務(wù),然後重新提交被拒絕的任務(wù)。如果阻塞隊(duì)列是優(yōu)先隊(duì)列,那麼「拋棄最舊的」策略將導(dǎo)致拋棄優(yōu)先順序最高的任務(wù),因此最好不要將該策略和優(yōu)先權(quán)隊(duì)列放在一起使用。

CallerRunsPolicy:呼叫者運(yùn)行策略。在呼叫者執(zhí)行緒中執(zhí)行該任務(wù)。該策略實(shí)現(xiàn)了一種調(diào)節(jié)機(jī)制,該策略既不會(huì)拋棄任務(wù),也不會(huì)拋出異常,而是將任務(wù)回退到呼叫者(調(diào)用線程池執(zhí)行任務(wù)的主線程),由於執(zhí)行任務(wù)需要一定時(shí)間,因此主執(zhí)行緒至少在一段時(shí)間內(nèi)不能提交任務(wù),這使得執(zhí)行緒池有時(shí)間處理完正在執(zhí)行的任務(wù)。

46、List、Set、Map三者的差異?

List(對(duì)付順序的好幫手):List 介面儲(chǔ)存一組不唯一(可以有多個(gè)元素引用相同的物件)、有序的物件。

Set(著重獨(dú)一無二的性質(zhì)):不允許重複的集合,不會(huì)有多個(gè)元素引用相同的物件。

Map(用Key來搜尋的專業(yè)戶): 使用鍵值對(duì)儲(chǔ)存。 Map 會(huì)維護(hù)與 Key 有關(guān)聯(lián)的值。兩個(gè) Key可以引用相同的對(duì)象,但 Key 不能重複,典型的 Key 是String類型,但也可以是任何對(duì)象。

47、ArrayList 和 LinkedList 的差異。

ArrayList 底層基於動(dòng)態(tài)數(shù)組實(shí)現(xiàn),LinkedList 底層基於鍊錶實(shí)作。

對(duì)於按index 索引資料(get/set方法):ArrayList 透過index 直接定位到陣列對(duì)應(yīng)位置的節(jié)點(diǎn),而LinkedList需要從頭結(jié)點(diǎn)或尾節(jié)點(diǎn)開始遍歷,直到尋找目標(biāo)節(jié)點(diǎn),因此在效率上ArrayList 優(yōu)於LinkedList。

對(duì)於隨機(jī)插入和刪除:ArrayList 需要移動(dòng)目標(biāo)節(jié)點(diǎn)後面的節(jié)點(diǎn)(使用System.arraycopy 方法移動(dòng)節(jié)點(diǎn)),而LinkedList 只需修改目標(biāo)節(jié)點(diǎn)前後節(jié)點(diǎn)的next 或prev 屬性即可,因此在效率上LinkedList 優(yōu)於ArrayList。

對(duì)於順序插入和刪除:由於 ArrayList 不需要移動(dòng)節(jié)點(diǎn),因此在效率上比 LinkedList 更好。這也是為什麼在實(shí)際使用中 ArrayList 更多,因?yàn)榇蟛糠智闆r下我們的使用都是順序插入。

48、ArrayList 和 Vector 的區(qū)別。

Vector 和 ArrayList 幾乎一致,唯一的差異在於 Vector 在方法上使用了 synchronized 來保證執(zhí)行緒安全,因此在效能上 ArrayList 具有更好的表現(xiàn)。

有類似關(guān)係的還有:StringBuilder 和 StringBuffer、HashMap 和 Hashtable。

49、介紹下HashMap 的底層資料結(jié)構(gòu)

我們現(xiàn)在用的都是JDK 1.8,底層是由「陣列鍊錶紅黑樹」組成,如下圖,而在JDK 1.8 之前是由「數(shù)組鍊錶」組成。

50、為什麼要改成「陣列 鍊錶 紅黑樹」?

主要是為了提昇在 hash 衝突嚴(yán)重時(shí)(鍊錶過長(zhǎng))的尋找效能,使用鍊錶的尋找效能是 O(n),而使用紅黑樹是 O(logn)。

51、那在什麼時(shí)候用鍊錶?什麼時(shí)候用紅黑樹?

對(duì)於插入,預(yù)設(shè)是使用鍊錶節(jié)點(diǎn)。當(dāng)同一個(gè)索引位置的節(jié)點(diǎn)在新增後超過8個(gè)(閾值8):如果此時(shí)數(shù)組長(zhǎng)度大於等於64,則會(huì)觸發(fā)鍊錶節(jié)點(diǎn)轉(zhuǎn)紅黑樹節(jié)點(diǎn)(treeifyBin);而如果數(shù)組長(zhǎng)度小於64,則不會(huì)觸發(fā)鍊錶轉(zhuǎn)紅黑樹,而是會(huì)進(jìn)行擴(kuò)容,因?yàn)榇藭r(shí)的資料量還比較小。

對(duì)於移除,當(dāng)同一個(gè)索引位置的節(jié)點(diǎn)在移除後達(dá)到 6 個(gè),並且該索引位置的節(jié)點(diǎn)為紅黑樹節(jié)點(diǎn),會(huì)觸發(fā)紅黑樹節(jié)點(diǎn)轉(zhuǎn)鍊錶節(jié)點(diǎn)(untreeify)。

52、HashMap 的預(yù)設(shè)初始容量是多少? HashMap 的容量有什麼限制嗎?

預(yù)設(shè)初始容量是16。 HashMap 的容量必須是2的N次方,HashMap 會(huì)根據(jù)我們傳入的容量計(jì)算一個(gè)大於等於該容量的最小的2的N次方,例如傳 9,容量為16。

53、HashMap 的插入流程是怎麼樣的?

54、HashMap 的擴(kuò)容(resize)流程是怎麼樣的?

55、除了 HashMap,還用過哪些 Map,使用時(shí)怎麼選擇?

56、HashMap?和Hashtable?的差異?

HashMap 允許 key 和 value 為 null,Hashtable 不允許。

HashMap 的預(yù)設(shè)初始容量為 16,Hashtable 為 11。

HashMap 的擴(kuò)容為原來的 2 倍,Hashtable 的擴(kuò)容為原來的 2 倍加 1。

HashMap 是非線程安全的,Hashtable是線程安全的。

HashMap 的 hash 值重新計(jì)算過,Hashtable 直接使用 hashCode。

HashMap 去掉了 Hashtable 中的 contains 方法。

HashMap 繼承自 AbstractMap 類,Hashtable 繼承自 Dictionary 類別。

57、Java 記憶體結(jié)構(gòu)(執(zhí)行階段資料區(qū))

程式計(jì)數(shù)器:執(zhí)行緒私有。一塊較小的記憶體空間,可以看作目前執(zhí)行緒所執(zhí)行的字節(jié)碼的行號(hào)指示器。如果執(zhí)行緒正在執(zhí)行的是一個(gè)Java方法,這個(gè)計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)器字節(jié)碼指令的位址;如果正在執(zhí)行的是Native方法,這個(gè)計(jì)數(shù)器值則是空。

Java虛擬機(jī)器堆疊:執(zhí)行緒私有。它的生命週期與線程相同。虛擬機(jī)器棧描述的是Java方法執(zhí)行的記憶體模型:每個(gè)方法在執(zhí)行的同時(shí)都會(huì)建立一個(gè)堆疊幀用於儲(chǔ)存局部變數(shù)表、操作數(shù)棧、動(dòng)態(tài)連結(jié)、方法出口等資訊。每一個(gè)方法從呼叫直到執(zhí)行完成的過程,就對(duì)應(yīng)一個(gè)堆疊幀在虛擬機(jī)器棧中入棧到出棧的過程。

本地方法堆疊:執(zhí)行緒私有。本機(jī)方法棧與虛擬機(jī)棧所扮演的角色是非常相似的,它們之間的差異不過是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則為虛擬機(jī)器使用到的Native方法服務(wù)。

Java堆:執(zhí)行緒共享。對(duì)大多數(shù)應(yīng)用程式來說,Java堆是Java虛擬機(jī)器所管理的記憶體中最大的一塊。 Java堆是被所有執(zhí)行緒共享的一塊記憶體區(qū)域,在虛擬機(jī)器啟動(dòng)時(shí)創(chuàng)建。此記憶體區(qū)域的唯一目的就是存放物件實(shí)例,幾乎所有的物件實(shí)例都在這裡分配記憶體。

方法區(qū):與Java堆一樣,是各個(gè)執(zhí)行緒共享的記憶體區(qū)域,它用於儲(chǔ)存已被虛擬機(jī)器載入的類別資訊(建構(gòu)方法、介面定義)、常數(shù)、靜態(tài)變數(shù)、即時(shí)編譯器編譯後的程式碼(字節(jié)碼)等數(shù)據(jù)。方法區(qū)是JVM規(guī)範(fàn)中定義的一個(gè)概念,具體放在哪裡,不同的實(shí)作可以放在不同的地方。

運(yùn)行時(shí)常量池:運(yùn)行時(shí)常量池是方法區(qū)的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項(xiàng)信息是常量池,用于存放編譯期生成的各種字面量和符號(hào)引用,這部分內(nèi)容將在類加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放。

String?str?=?new?String("hello");

上面的語(yǔ)句中變量 str 放在棧上,用 new 創(chuàng)建出來的字符串對(duì)象放在堆上,而"hello"這個(gè)字面量是放在堆中。

58、什么是雙親委派模型?

如果一個(gè)類加載器收到了類加載的請(qǐng)求,它首先不會(huì)自己去嘗試加載這個(gè)類,而是把這個(gè)請(qǐng)求委派給父類加載器去完成,每一個(gè)層次的類加載器都是如此,因此所有的加載請(qǐng)求最終都應(yīng)該傳送到頂層的啟動(dòng)類加載器中,只有當(dāng)父加載器反饋?zhàn)约簾o法完成這個(gè)加載請(qǐng)求(它的搜索范圍中沒有找到所需的類)時(shí),子加載器才會(huì)嘗試自己去加載。

59、Java虛擬機(jī)中有哪些類加載器?

啟動(dòng)類加載器(Bootstrap ClassLoader):

這個(gè)類加載器負(fù)責(zé)將存放在\lib目錄中的,或者被-Xbootclasspath參數(shù)所指定的路徑中的,并且是虛擬機(jī)識(shí)別的(僅按照文件名識(shí)別,如rt.jar,名字不符合的類庫(kù)即使放在lib目錄中也不會(huì)被加載)類庫(kù)加載到虛擬機(jī)內(nèi)存中。

擴(kuò)展類加載器(Extension ClassLoader):

這個(gè)加載器由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn),它負(fù)責(zé)加載\lib\ext目錄中的,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫(kù),開發(fā)者可以直接使用擴(kuò)展類加載器。

應(yīng)用程序類加載器(Application ClassLoader):

這個(gè)類加載器由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)。由于這個(gè)類加載器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也稱它為系統(tǒng)類加載器。它負(fù)責(zé)加載用戶類路徑(ClassPath)上所指定的類庫(kù),開發(fā)者可以直接使用這個(gè)類加載器,如果應(yīng)用程序中沒有自定義過自己的類加載器,一般情況下這個(gè)就是程序中默認(rèn)的類加載器。

自定義類加載器:

用戶自定義的類加載器。

60、類加載的過程

類加載的過程包括:加載、驗(yàn)證、準(zhǔn)備、解析、初始化,其中驗(yàn)證、準(zhǔn)備、解析統(tǒng)稱為連接。

加載:通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流,在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象。

驗(yàn)證:確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)自身的安全。

準(zhǔn)備:為靜態(tài)變量分配內(nèi)存并設(shè)置靜態(tài)變量初始值,這里所說的初始值“通常情況”下是數(shù)據(jù)類型的零值。

解析:將常量池內(nèi)的符號(hào)引用替換為直接引用。

初始化:到了初始化階段,才真正開始執(zhí)行類中定義的 Java 初始化程序代碼。主要是靜態(tài)變量賦值動(dòng)作和靜態(tài)語(yǔ)句塊(static{})中的語(yǔ)句。

61、介紹下垃圾收集機(jī)制(在什么時(shí)候,對(duì)什么,做了什么)?

在什么時(shí)候?

在觸發(fā)GC的時(shí)候,具體如下,這里只說常見的 Young GC 和 Full GC。

觸發(fā)Young GC:當(dāng)新生代中的 Eden 區(qū)沒有足夠空間進(jìn)行分配時(shí)會(huì)觸發(fā)Young GC。

觸發(fā)Full GC:

  • 當(dāng)準(zhǔn)備要觸發(fā)一次Young GC時(shí),如果發(fā)現(xiàn)統(tǒng)計(jì)數(shù)據(jù)說之前Young GC的平均晉升大小比目前老年代剩余的空間大,則不會(huì)觸發(fā)Young GC而是轉(zhuǎn)為觸發(fā)Full GC。(通常情況)
  • 如果有永久代的話,在永久代需要分配空間但已經(jīng)沒有足夠空間時(shí),也要觸發(fā)一次Full GC。
  • System.gc()默認(rèn)也是觸發(fā)Full GC。
  • heap dump帶GC默認(rèn)也是觸發(fā)Full GC。
  • CMS GC時(shí)出現(xiàn)Concurrent Mode Failure會(huì)導(dǎo)致一次Full GC的產(chǎn)生。

對(duì)什么?

對(duì)那些JVM認(rèn)為已經(jīng)“死掉”的對(duì)象。即從GC Root開始搜索,搜索不到的,并且經(jīng)過一次篩選標(biāo)記沒有復(fù)活的對(duì)象。

做了什么?

對(duì)這些JVM認(rèn)為已經(jīng)“死掉”的對(duì)象進(jìn)行垃圾收集,新生代使用復(fù)制算法,老年代使用標(biāo)記-清除和標(biāo)記-整理算法。

62、GC Root有哪些?

在Java語(yǔ)言中,可作為GC Roots的對(duì)象包括下面幾種:

  • 虛擬機(jī)器堆疊(堆疊框架中的本機(jī)變數(shù)表)中所引用的物件。
  • 方法區(qū)中類別靜態(tài)屬性所引用的物件。
  • 方法區(qū)中常數(shù)引用的物件。
  • 本地方法堆疊中JNI(即一般說的Native方法)所引用的物件。

63、垃圾收集有哪些演算法,各自的特色?

標(biāo)記 - 清除演算法

首先標(biāo)記所有需要回收的對(duì)象,在標(biāo)記完成後統(tǒng)一回收所有被標(biāo)記的對(duì)象。它的主要不足有兩個(gè):一個(gè)是效率問題,標(biāo)記和清除兩個(gè)過程的效率都不高;另一個(gè)是空間問題,標(biāo)記清除之後會(huì)產(chǎn)生大量不連續(xù)的記憶體碎片,空間碎片太多可能會(huì)導(dǎo)致以後在程式運(yùn)行過程中需要分配較大物件時(shí),無法找到足夠的連續(xù)記憶體而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。

複製演算法

為了解決效率問題,一種稱為「複製」(Copying)的收集演算法出現(xiàn)了,它將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)這一塊的記憶體用完了,就將還存活著的物件複製到另外一塊上面,然後再把已使用過的記憶體空間一次清理掉。這使得每次都是對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等複雜情況,只要移動(dòng)堆頂指針,按順序分配內(nèi)存即可,實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效。只是這種演算法的代價(jià)是將記憶體縮小為了原來的一半,未免太高了一點(diǎn)。

標(biāo)記 - 整理演算法

複製收集演算法在物件存活率較高時(shí)就要進(jìn)行較多的複製操作,效率將會(huì)變低。更關(guān)鍵的是,如果不想浪費(fèi)50%的空間,就需要有額外的空間進(jìn)行分配擔(dān)保,以應(yīng)對(duì)被使用的內(nèi)存中所有對(duì)像都100%存活的極端情況,所以在老年代一般不能直接選用這種演算法.

根據(jù)老年代的特點(diǎn),有人提出了另外一種「標(biāo)記-整理」(Mark-Compact)演算法,標(biāo)記過程仍然與「標(biāo)記-清除」演算法一樣,但後續(xù)步驟不是直接對(duì)可回收物件進(jìn)行清理,而是讓所有存活的物件都向一端移動(dòng),然後直接清理掉端邊界以外的記憶體。

分代收集演算法

目前商業(yè)虛擬機(jī)的垃圾收集都採(cǎi)用「分代收集」(Generational Collection)演算法,這種演算法並沒有什麼新的思想,只是根據(jù)物件存活週期的不同將記憶體劃分為幾塊。

通常是把Java堆分成新生代和老年代,這樣就可以根據(jù)各個(gè)年代的特徵採(cǎi)用最適當(dāng)?shù)氖占菟惴ā?

在新生代中,每次垃圾收集時(shí)都發(fā)現(xiàn)有一大批物件死去,只有少量存活,那就選用複製演算法,只需要付出少量存活對(duì)象的複製成本就可以完成收集。

在老年代中因?yàn)槲锛婊盥矢摺]有額外空間對(duì)它進(jìn)行分配擔(dān)保,就必須使用標(biāo)記—清理或標(biāo)記—整理演算法來進(jìn)行回收。

最後

金三銀四的季節(jié),相信有不少同學(xué)正準(zhǔn)備跳槽。

我將我最近的原創(chuàng)的文章進(jìn)行了匯總:原創(chuàng)匯總,其中有不少面試高頻題目解析,很多都是我自己在面試大廠時(shí)遇到的,我在對(duì)每個(gè)題目解析時(shí)都會(huì)以較高的標(biāo)準(zhǔn)進(jìn)行深入剖析,可能只看一遍並不能完全明白,但是相信反覆閱讀,定能有所收穫。

更多程式設(shè)計(jì)相關(guān)知識(shí),請(qǐng)?jiān)煸L:程式設(shè)計(jì)課程! !

以上是【吐血整理】2023年Java 基礎(chǔ)高頻面試題目及答案(收藏)的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願(yuàn)投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請(qǐng)聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁(yè)開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1597
29
PHP教程
1488
72
面試官:Spring Aop 常見註解和執(zhí)行順序 面試官:Spring Aop 常見註解和執(zhí)行順序 Aug 15, 2023 pm 04:32 PM

你一定知道 Spring , 那說說 Aop 的去全部通知順序, Spring Boot 或 Spring Boot 2 對(duì) aop 的執(zhí)行順序影響?說說你在 AOP 中遇到的那些坑?

某團(tuán)面試:如果線上遇到了OOM,該如何檢查?如何解決?哪些方案? 某團(tuán)面試:如果線上遇到了OOM,該如何檢查?如何解決?哪些方案? Aug 23, 2023 pm 02:34 PM

OOM 意味著程式存在漏洞,可能是程式碼或 JVM 參數(shù)配置引起的。這篇文章跟讀者聊聊,Java 進(jìn)程觸發(fā)了 OOM 後如何排查。

餓了麼筆試題,看似簡(jiǎn)單,難倒一批人 餓了麼筆試題,看似簡(jiǎn)單,難倒一批人 Aug 24, 2023 pm 03:29 PM

在很多公司的筆試題中,千萬別小看,都是有坑的,一不小心自己就掉進(jìn)去了。遇到這種關(guān)於循環(huán)的筆試題,建議,自己冷靜思考,一步一步來。

上週,XX保險(xiǎn)面試,涼了! ! ! 上週,XX保險(xiǎn)面試,涼了! ! ! Aug 25, 2023 pm 03:44 PM

上週,一位群組裡的朋友去平安保險(xiǎn)面試了,結(jié)果有些遺憾,蠻可惜的,但希望你不要?dú)怵H,正如你所說的,面試中遇到的問題,基本上都是可以通過背面試題解決的,所以請(qǐng)加油!

5道String面試題,能全答對(duì)的人不到10%! (附答案) 5道String面試題,能全答對(duì)的人不到10%! (附答案) Aug 23, 2023 pm 02:49 PM

這篇來看看 Java String類別的 5 題面試題,這五題,我自己在面試過程中親身經(jīng)歷過幾題目,本篇就帶你了解這些題的答案為什麼是這樣。

小白也能與BAT面試官對(duì)線:CAS 小白也能與BAT面試官對(duì)線:CAS Aug 24, 2023 pm 03:09 PM

Java並發(fā)程式設(shè)計(jì)系列番外篇C A S(Compare and swap),文章風(fēng)格依然是圖文並茂,簡(jiǎn)單易懂,讓讀者們也能與面試官瘋狂對(duì)線。

幾乎所有Java面試都會(huì)問到的問題:說ArrayList和LinkedList的差別 幾乎所有Java面試都會(huì)問到的問題:說ArrayList和LinkedList的差別 Jul 26, 2023 pm 03:11 PM

Java的資料結(jié)構(gòu)是面試考察的重點(diǎn),只要參與Java面試的同學(xué)相信都有所體會(huì)。面試官問這類問題的時(shí)候往往是想檢視你是否研究過Java中常用資料類型的底層結(jié)構(gòu),而不是只是簡(jiǎn)單的停留在"會(huì)使用"的層次。

面試官:說一下類別載入的過程(10張圖解) 面試官:說一下類別載入的過程(10張圖解) Aug 23, 2023 pm 03:05 PM

當(dāng)我們要使用一個(gè)類別的時(shí)候,要透過ClassLoader將類別載入到記憶體中。

See all articles