国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

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

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

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

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

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

1、物件導向的三個基本特徵?

物件導向的三個基本特徵是:封裝、繼承和多型。

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

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

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

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

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

同一個事件發(fā)生在不同的物件上會產生不同的結果。

我再舉一個簡單的例子幫助大家理解,這個例子可能不是完全準確,但是我認為是有利於理解的。

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

在這個例子中:

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

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

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

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

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

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

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

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

我們將程式碼區(qū)塊2進行編譯,字節(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入(操作數)棧
???????1:?istore_1?//?將棧頂int類型值保存到局部變量1中
???????2:?iload_1?//?從局部變量1中裝載int類型值入棧
???????3:?iconst_1?//?將int類型值1入棧
???????4:?iadd?//?將棧頂兩int類型數相加,結果入棧
???????5:?i2s?//?將棧頂int類型值截斷成short類型值,后帶符號擴展成int類型值入棧。
???????6:?istore_1?//?將棧頂int類型值保存到局部變量1中
???????7:?return
}

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

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

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

##4、基礎考察,指出下題的輸出結果
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,相當於執(zhí)行:Integer a = Integer.valueOf(128),基本類型自動轉換為包裝類別的過程稱為自動裝箱(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 來快取一定範圍的值,IntegerCache 預設範圍為:-128~127。

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

但是當這個快取範圍時可以修改的,可能有些人不知道??梢酝高^JVM啟動參數:-XX:AutoBoxCacheMax= 來修改上限值,如下圖所示:

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

2 << 3.

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

這可能就是所謂的「豬隊友」吧。

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

&&:邏輯與運算符。當運算符左右兩邊的表達式都為 true,才返回 true。同時具有短路性,如果第一個表達式為 false,則直接返回 false。

&:邏輯與運算符、按位與運算符。

按位與運算符:用于二進制的計算,只有對應的兩個二進位均為1時,結果位才為1 ,否則為0。

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

7、String 是 Java 基本數據類型嗎?

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

基本數據類型:數據直接存儲在棧上

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

8、String 類可以繼承嗎?

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

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

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

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

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

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

一個或兩個。如果字符串常量池已經有“xyz”,則是一個;否則,兩個。

當字符創(chuàng)常量池沒有 “xyz”,此時會創(chuàng)建如下兩個對象:

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

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

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

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

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

所以前者其實理解為被后者的所包含。

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

==:運算符,用于比較基礎類型變量和引用類型變量。

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

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

對于引用類型變量,比較的是兩個對象的地址是否相同。

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

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

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

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

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

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

不對。hashCode() 和 equals() 之間的關系如下:

當有 a.equals(b) == true 時,則 a.hashCode() == b.hashCode() 必然成立,

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

14、什么是反射

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

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

數據分為基本數據類型和引用數據類型?;緮祿愋停簲祿苯哟鎯υ跅V?;引用數據類型:存儲在棧中的是對象的引用地址,真實的對象數據存放在堆內存里。

淺拷貝:對于基礎數據類型:直接復制數據值;對于引用數據類型:只是復制了對象的引用地址,新舊對象指向同一個內存地址,修改其中一個對象的值,另一個對象的值隨之改變。

深拷貝:對于基礎數據類型:直接復制數據值;對于引用數據類型:開辟新的內存空間,在新的內存空間里復制一個一模一樣的對象,新老對象不共享內存,修改其中一個對象的值,不會影響另一個對象。

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

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

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

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

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

網上有個例子挺形象的:

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

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

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

17、構造器是否可被 重寫?

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

18、當一個對象被當作參數傳遞到一個方法后,此方法可改變這個對象的屬性,并可返回變化后的結果,那么這里到底是值傳遞還是引用傳遞?

值傳遞。Java 中只有值傳遞,對于對象參數,值的內容是對象的引用。

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

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

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

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

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

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

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

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

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

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

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

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

21、初始化考察,請指出下面程序的運行結果。

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() { // 父類構造器
        System.out.print("a");
    }
}
class B extends A {
    static { // 子類靜態(tài)代碼塊
        System.out.print("B");
    }
    public B() { // 子類構造器
        System.out.print("b");
    }
}

執(zhí)行結果:ABabab,兩個考察點:

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

2)當有父類時,完整的初始化順序為:父類靜態(tài)變量(靜態(tài)代碼塊)->子類靜態(tài)變量(靜態(tài)代碼塊)->父類非靜態(tài)變量(非靜態(tài)代碼塊)->父類構造器 ->子類非靜態(tài)變量(非靜態(tài)代碼塊)->子類構造器 。

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

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

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

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

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

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

如果我們有兩個方法如下,當我們調用:test(1) 時,編譯器無法確認要調用的是哪個。

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

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

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

抽象類只能單繼承,接口可以多實現。

抽象類可以有構造方法,接口中不能有構造方法。

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

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

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

設計思想的區(qū)別:

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

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

我在網上看到有個說法,挺形象的:

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

抽象類像叔伯,有一部分會給你,還能指導你做事的方法。

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

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

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

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

Exception 表示需要捕捉或者需要程序進行處理的異常,是一種設計或實現問題,也就是說,它表示如果程序運行正常,從不會發(fā)生的情況。

26、Java 中的 final 關鍵字有哪些用法?

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

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

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

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ū)別。

其實是三個完全不相關的東西,只是長的有點像。。

final 如上所示。

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

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

28、try、catch、finally 考察,請指出下面程序的運行結果。

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í)行結果:31。

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

29、try、catch、finally 考察2,請指出下面程序的運行結果。

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

執(zhí)行結果:3。

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

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

30、try、catch、finally 考察3,請指出下面程序的運行結果。

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í)行結果:2。

這邊估計有不少同學會以為結果應該是 3,因為我們知道在 return 前會執(zhí)行 finally,而 i 在 finally 中被修改為 3 了,那最終返回 i 不是應該為 3 嗎?確實很容易這么想,我最初也是這么想的,當初的自己還是太年輕了啊。

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

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

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

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

介面預設方法:Java 8允許我們?yōu)榻槊嫣砑右粋€非抽象的方法實現,只需要使用default關鍵字即可

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

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

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

日期時間API:Java 8 引進了新的日期時間API改進了日期時間的管理。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

start():新啟動一個線程,這時此線程處於就緒(可運行)狀態(tài),並沒有運行,一旦得到 CPU 時間片,就開始執(zhí)行 run() 方法。

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

#一個執(zhí)行緒可以處於下列狀態(tài)之一:

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

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

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

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

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

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

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

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

1)Lock 是一個接口;synchronized 是 Java 中的關鍵字,synchronized 是內置的語言實現;

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

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

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

39、synchronized 各種加鎖場景的作用范圍

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

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

2.作用于靜態(tài)方法,鎖住的是類的Class對象,因為Class的相關數據存儲在永久代元空間,元空間是全局共享的,因此靜態(tài)方法鎖相當于類的一個全局鎖,會鎖所有調用該方法的線程。

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

3.作用于 Lock.class,鎖住的是 Lock 的Class對象,也是全局只有一個。

synchronized?(Lock.class)?{}

4.作用于 this,鎖住的是對象實例,每一個對象實例有一個鎖。

synchronized?(this)?{}

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

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

40、如何檢測死鎖?

死鎖的四個必要條件:

1)互斥條件:進程對所分配到的資源進行排他性控制,即在一段時間內某資源僅為一個進程所占有。此時若有其他進程請求該資源,則請求進程只能等待。

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

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

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

41、怎么預防死鎖?

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

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

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

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

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

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

如果我們在方法中直接new一個線程來處理,當這個方法被呼叫頻繁時就會創(chuàng)建很多線程,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性,一不小心把系統(tǒng)搞崩了,就可以直接去財務結帳了。

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

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

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

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

corePoolSize(核心執(zhí)行緒數):當執(zhí)行緒池執(zhí)行的執(zhí)行緒少於 corePoolSize 時,將建立一個新執(zhí)行緒來處理請求,即使其他工作執(zhí)行緒處於空閒狀態(tài)。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

47、ArrayList 和 LinkedList 的差異。

ArrayList 底層基於動態(tài)數組實現,LinkedList 底層基於鍊錶實作。

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

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

對於順序插入和刪除:由於 ArrayList 不需要移動節(jié)點,因此在效率上比 LinkedList 更好。這也是為什麼在實際使用中 ArrayList 更多,因為大部分情況下我們的使用都是順序插入。

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

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

有類似關係的還有:StringBuilder 和 StringBuffer、HashMap 和 Hashtable。

49、介紹下HashMap 的底層資料結構

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

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

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

51、那在什麼時候用鍊錶?什麼時候用紅黑樹?

對於插入,預設是使用鍊錶節(jié)點。當同一個索引位置的節(jié)點在新增後超過8個(閾值8):如果此時數組長度大於等於64,則會觸發(fā)鍊錶節(jié)點轉紅黑樹節(jié)點(treeifyBin);而如果數組長度小於64,則不會觸發(fā)鍊錶轉紅黑樹,而是會進行擴容,因為此時的資料量還比較小。

對於移除,當同一個索引位置的節(jié)點在移除後達到 6 個,並且該索引位置的節(jié)點為紅黑樹節(jié)點,會觸發(fā)紅黑樹節(jié)點轉鍊錶節(jié)點(untreeify)。

52、HashMap 的預設初始容量是多少? HashMap 的容量有什麼限制嗎?

預設初始容量是16。 HashMap 的容量必須是2的N次方,HashMap 會根據我們傳入的容量計算一個大於等於該容量的最小的2的N次方,例如傳 9,容量為16。

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

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

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

56、HashMap?和Hashtable?的差異?

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

HashMap 的預設初始容量為 16,Hashtable 為 11。

HashMap 的擴容為原來的 2 倍,Hashtable 的擴容為原來的 2 倍加 1。

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

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

HashMap 去掉了 Hashtable 中的 contains 方法。

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

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

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

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

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

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

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

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

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

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

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

如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每一個層次的類加載器都是如此,因此所有的加載請求最終都應該傳送到頂層的啟動類加載器中,只有當父加載器反饋自己無法完成這個加載請求(它的搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載。

59、Java虛擬機中有哪些類加載器?

啟動類加載器(Bootstrap ClassLoader):

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

擴展類加載器(Extension ClassLoader):

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

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

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

自定義類加載器:

用戶自定義的類加載器。

60、類加載的過程

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

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

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

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

解析:將常量池內的符號引用替換為直接引用。

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

61、介紹下垃圾收集機制(在什么時候,對什么,做了什么)?

在什么時候?

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

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

觸發(fā)Full GC:

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

對什么?

對那些JVM認為已經“死掉”的對象。即從GC Root開始搜索,搜索不到的,并且經過一次篩選標記沒有復活的對象。

做了什么?

對這些JVM認為已經“死掉”的對象進行垃圾收集,新生代使用復制算法,老年代使用標記-清除和標記-整理算法。

62、GC Root有哪些?

在Java語言中,可作為GC Roots的對象包括下面幾種:

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

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

標記 - 清除演算法

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

複製演算法

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

標記 - 整理演算法

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

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

分代收集演算法

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

通常是把Java堆分成新生代和老年代,這樣就可以根據各個年代的特徵採用最適當的收集演算法。

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

在老年代中因為物件存活率高、沒有額外空間對它進行分配擔保,就必須使用標記—清理或標記—整理演算法來進行回收。

最後

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

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

更多程式設計相關知識,請造訪:程式設計課程! !

以上是【吐血整理】2023年Java 基礎高頻面試題目及答案(收藏)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發(fā)現涉嫌抄襲或侵權的內容,請聯(lián)絡admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

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

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

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

面試官:Spring Aop 常見註解和執(zhí)行順序 面試官:Spring Aop 常見註解和執(zhí)行順序 Aug 15, 2023 pm 04:32 PM

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

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

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

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

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

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

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

上週,XX保險面試,涼了! ! ! 上週,XX保險面試,涼了! ! ! Aug 25, 2023 pm 03:44 PM

上週,一位群組裡的朋友去平安保險面試了,結果有些遺憾,蠻可惜的,但希望你不要氣餒,正如你所說的,面試中遇到的問題,基本上都是可以通過背面試題解決的,所以請加油!

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

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

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

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

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

當我們要使用一個類別的時候,要透過ClassLoader將類別載入到記憶體中。

See all articles