超全面!阿里巴巴最新發布22年秋招200道Java面試題(含答案)

程序猿凱撒 發佈 2022-06-27T10:42:20.676174+00:00

馬上過34歲生日了,和大家聊聊最近的情況半年前還在迷茫該學什麼,怎樣才能走出現在的困境,半年後已經成功上岸阿里,感謝在這期間幫助我的每一個人。

馬上過34歲生日了,和大家聊聊最近的情況
半年前還在迷茫該學什麼,怎樣才能走出現在的困境,半年後已經成功上岸阿里,感謝在這期間幫助我的每一個人。

面試中總結了200道經典的Java面試題,裡面包含面試要回答的知識重點,並且我根據知識類型進行了分類,可以說非常全面了~

java平台相關

1、JDK、jre、jvm 分別是什麼關係? 2、為什麼 Java 被稱作是「平台無關的程式語言」? 3、Java 和 C++ 的區別? 4、什麼是字節碼?採用字節碼的最大好處是什麼? 5、Java運行的過程? 6、Java是動態類型語言還是靜態類型語言?

面向對象

7.什麼是面向對象? 8.請說說面向對象的特徵?封裝、繼承、多態分別說一下,以及它們的好處? 9.多態為什麼要轉型? 10.說一下權限修飾符的使用權限?

語言基礎

  • 基本數據類型和引用類型

11.Java 中的幾種基本數據類型是什麼?各自占用多少字節? 12.char 型變量中能不能存貯一個中文漢字?為什麼? 13.什麼是引用類型? 14.什麼是值傳遞和引用傳遞? 15.屬性(欄位)和變量的區別? 16.什麼是重載和重寫?Overload(重載)和override(重寫)的區別? 17.什麼是java序列化,如何實現java序列化?或者請解釋serializable接口的作用?

  • 字符串相關

18.String 為什麼是不可變的? 19.String s = new String("xyz") 會創建幾個對象? 20.說說你對字符串常量池的理解? 21.String、StringBuffer、StringBuilder 的區別? 22.談談你對this關鍵字的理解? 23.談談你對super關鍵字的理解? 24.那你知道this和super有什麼區別嗎? 25.談談你對static關鍵字的理解? 26.談談你對final關鍵字的理解?

27.你知道在Java中都有哪裡用到了哈希 嗎?

  • 拷貝相關

28.Java中有多少種拷貝類型?分別說一下? 29.那你碰到過多引用拷貝嗎?知道怎麼解決嗎?

  • 接口相關

30.你平時是怎麼使用接口的?談談你的理解? 31.那聽你這麼說,接口的實現類的方法返回值類型是什麼? 32.方法的參數可以是接口嗎? 33.接口的返回值類型可否是另一個接口類型?

  • 抽象類

34.接口引用調用實現類方法? 35.抽象類使用規則 36.抽象類注意事項? 37.Abstractclass和interface語法上有什麼區別? 38.接口是否可繼承接口?抽象類是否可繼承具體類(concreteclass)?抽象類中是否可以有靜態的main方法?

  • 包裝類

39.什麼是自動拆裝箱? 40.為什麼要轉換?

  • 泛型

41.你平時是如何使用泛型的?

  • 異常

42.Exeception和Error區別? 43.那你知道異常有幾種處理方式嗎? 44.說說Throwable類怎麼用吧? 45.你最常見到的是Java中的什麼異常?

  • 反射機制

46.什麼是反射機制? 47.那怎麼使用反射呢? 48.你反射這麼熟悉,那一般在哪些場景用到它啊? 49.聽你說的這麼多,那它就沒有缺點嗎?

  • JDK1.8新特性

50.你知道JDK1.8有哪些新特性嗎?

以下是答案:

Java平台相關

1、JDK、JRE、JVM 分別是什麼關係?

JDK 即為 Java 開發工具包,包含編寫 Java 程序所必須的編譯、運行等開發工具以及 JRE。開發工具如:
用於編譯 Java 程序的 javac 命令。
用於啟動 JVM 運行 Java 程序的 Java 命令。
用於生成文檔的 Javadoc 命令。
用於打包的 jar 命令等等。

2、為什麼 Java 被稱作是「平台無關的程式語言」?

Java 虛擬機是一個可以執行 Java 字節碼的虛擬機進程。
Java 源文件( `.java` )被編譯成能被 Java 虛擬機執行的字節碼文件( `.class` )。
Java 被設計成允許應用程式可以運行在任意的平台,而不需要程式設計師為每一個平台單獨重寫或者是重新編譯。Java 虛擬機讓這個變為可能,因為它知道底層硬體平台的指令長度和其他特性。

3、Java 和 C++ 的區別?

都是面向對象的語言,都支持封裝、繼承和多態。
Java 不提供指針來直接訪問內存,程序內存更加安全。
Java 的類是單繼承的,C++ 支持多重繼承;雖然 Java 的類不可以多繼承,但是接口可以多繼承。
Java 有自動內存管理機制,不需要程式設計師手動釋放無用內存。

4、什麼是字節碼?採用字節碼的最大好處是什麼?

Java 中引入了虛擬機的概念,即在機器和編譯程序之間加入了一層抽象的虛擬的機器。這台虛擬的機器在任何平台上都提供給編譯程序一個的共同的接口。

編譯程序只需要面向虛擬機,生成虛擬機能夠理解的代碼,然後由解釋器來將虛擬機代碼轉換為特定系統的機器碼執行。在 Java 中,這種供虛擬機理解的代碼叫做字節碼(即擴展名為 `.class` 的文件),它不面向任何特定的處理器,只面向虛擬機。
​
每一種平台的解釋器是不同的,但是實現的虛擬機是相同的。Java 源程序經過編譯器編譯後變成字節碼,字節碼由虛擬機解釋執行,虛擬機將每一條要執行的字節碼送給解釋器,解釋器將其翻譯成特定機器上的機器碼,然後在特定的機器上運行。這也就是解釋了 Java 的編譯與解釋並存的特點。
​
採用字節碼的好處:
Java 語言通過字節碼的方式,在一定程度上解決了傳統解釋型語言執行效率低的問題,同時又保留了解釋型語言可移植的特點。所以 Java 程序運行時比較高效,而且,由於字節碼並不專對一種特定的機器,因此,Java程序無須重新編譯便可在多種不同的計算機上運行。

5、Java運行的過程?

Java 原始碼=> 編譯器 => JVM 可執行的 Java 字節碼(即虛擬指令)=> JVM => JVM 中解釋器 => 機器可執行的二進位機器碼 => 程序運行

6、Java是動態類型語言還是靜態類型語言?

動態類型語言和靜態類型語言兩者的卻別就在於對類型的檢查是在編譯期還是在運行期,滿足前者就是靜態類型語言,反之則是動態類型語言。
直白來說靜態語言是判斷變量自身的類型信息;動態類型語言是判斷變量值的類型信息,變量設有類型信息,變量值才有類型信息,這是動態語言的一個重要特徵。
​
Java是靜態類型語言(儘管lambda表達式為其增加了動態特性),js,python是動態類型語言。

面向對象

7.什麼是面向對象?

面向對象是一種思想,世間萬物都可以看做一個對象,這裡只討論面向對象編程(OOP),Java 是一個支持並發、基於類和面向對象的計算機高級程式語言。面向對象軟體開發具有以下優點:
代碼開發模塊化,更易維護和修改。
代碼復用性強。
增加代碼的可讀性。

8.請說說面向對象的特徵?封裝、繼承、多態分別說一下,以及它們的好處?

1.封裝:封裝,給對象提供了隱藏內部特性和行為的能力。對象提供一些能被其他對象訪問的方法來改變它內部的數據。在 Java 當中,有 4 種修飾符: `default`、`public`、`private` 和 `protected` 。每一種修飾符給其他的位於同一個包或者不同包下面對象賦予了不同的訪問權限。
​
使用封裝的一些好處:
 通過隱藏對象的屬性來保護對象內部的狀態。
 提高了代碼的可用性和可維護性,因為對象的行為可以被單獨的改變或者是擴展。
 禁止對象之間的不良交互提高模塊化。
​
2.繼承:繼承,給對象提供了從基類獲取欄位和方法的能力。繼承提供了代碼的重用行,也可以在不修改類的情況下給現存的類添加新特性。
​
3.多態:多態,是程式語言給不同的底層數據類型做相同的接口展示的一種能力。一個多態類型上的操作,可以應用到其他類型的值上面。
多態中,父類作為形參的方法和子類作為形參的方法都是一樣的。形參父類類型可以接收子類對象。這是多態的特性。
​
重要特性:轉型
向上轉型:父類引用指向子類對象。相當於子類對象賦給父類引用。這樣子,是默認的。子類的方法可以重寫父類的方法。但是,向上轉型的弊端就是只能使用父類有的方法,一旦向上轉型就不能調用子類特有的方法。所以需要向下轉型還原。
​
向下轉型:其實是一個還原的步驟。子類引用指向父類的一個引用。這個要強轉類型。因為我們父類不能去拿子類已經有的東西。所以必須把父類轉化為和子類一個類型。

9.多態為什麼要轉型?

當使用多態方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤。也就是說,不能調用子類擁有,而父類沒有的方法。編譯都錯誤,更別說運行了。這也是多態給我們帶來的一點"小麻煩」。所以,想要調用子類特有的方法,必須做向下轉型。

10.說一下權限修飾符的使用權限?

同一個類:四個都能訪問。
​
同一個包不同類:public、protected和defaut都能訪問。private不能訪問
​
不同包但是B類是A類的子類:
首先,必須導包。如果要用B類繼承A類,必須先導入A類所在的包。
public和protect能訪問。default不能訪問。private也不能。
​
不同包非子類:一點關係沒有。兩個類是陌生關係。不是一個包里的也沒有繼承(實現)關係。
只有public可以訪問。其他都不行。

語言基礎

  • 基本數據類型和引用類型

11.Java 中的幾種基本數據類型是什麼?各自占用多少字節?

基本數據類型如下:
byte 1位元組
boolean false/true(理論上占用1bit,1/8位元組,實際處理按1byte處理)
char 2位元組(C語言中是1位元組)
short 2位元組
int 4位元組
long 8位元組
float 4位元組
double 8位元組

12.char 型變量中能不能存貯一個中文漢字?為什麼?

在 Java 語言中,char 類型占 2 個字節,而且 Java 默認採用 Unicode 編碼,一個 Unicode 碼是 16 位,所以一個 Unicode 碼占兩個字節。
Java 中無論漢字還是英文字母,都是用 Unicode 編碼來表示的。所以,在 Java 中,char 類型變量可以存儲一個中文漢字。

13.什麼是引用類型?

引用類型聲明的變量是指該變量在內存中實際存儲的是一個引用地址,實體在堆中。
引用類型包括類、接口、數組等。
特別注意,String 是引用類型不是基本類型。

14.什麼是值傳遞和引用傳遞?

值傳遞,是對基本型變量而言的,傳遞的是該變量的一個副本,改變副本不影響原變量。
引用傳遞,一般是對於對象型變量而言的,傳遞的是該對象地址的一個副本,並不是原對象本身。
一般認為,Java 內的傳遞都是值傳遞,Java 中實例對象的傳遞是引用傳遞。

15.屬性(欄位)和變量的區別?

欄位是成員變量,是在類中聲明的變量。
變量可以分為局部變量和成員變量。成員變量就是欄位也叫做屬性。
所以欄位就是屬性就是成員變量。

16.什麼是重載和重寫?Overload(重載)和Override(重寫)的區別?

重載:Overload就是重載的意思。
​
重載Overload表示同一個類中可以有多個名稱相同的方法,但這些方法的參數列表各不相同(即參數個數或類型不同)。
Overload對我們來說可能比較熟悉,可以翻譯為重載,它是指我們可以定義一些名稱相同的方法,通過定義不同的輸入參數來區分這些方法,然後再調用時,JVM就會根據不同的參數樣式,來選擇合適的方法執行。在使用重載要注意以下的幾點:
1、在使用重載時只能通過不同的參數樣式。
例如,不同的參數類型,不同的參數個數,不同的參數順序(當然,同一方法內的幾個參數類型必須不一樣,例如可以是fun(int,float),但是不能為fun(int,int));
2、不能通過訪問權限、返回類型、拋出的異常進行重載;
3、方法的異常類型和數目不會對重載造成影響;
4、對於繼承來說,如果某一方法在父類中是訪問權限是priavte,那麼就不能在子類對其進行重載,如果定義的話,也只是定義了一個新方法,而不會達到重載的效果。
​
重寫:Override是覆蓋的意思,也就是重寫。
​
重寫Override表示子類中的方法可以與父類中的某個方法的名稱和參數完全相同,通過子類創建的實例對象調用這個方法時,將調用子類中的定義方法,這相當於把父類中定義的那個完全相同的方法給覆蓋了,這也是面向對象編程的多態性的一種表現。
子類覆蓋父類的方法時,只能比父類拋出更少的異常,或者是拋出父類拋出的異常的子異常,因為子類可以解決父類的一些問題,不能比父類有更多的問題。子類方法的訪問權限只能比父類的更大,不能更小。如果父類的方法是private類型,那麼,子類則不存在覆蓋的限制,相當於子類中增加了一個全新的方法。
​
override可以翻譯為覆蓋,從字面就可以知道,它是覆蓋了一個方法並且對其重寫,以求達到不同的作用。對我們來說最熟悉的覆蓋就是對接口方法的實現,在接口中一般只是對方法進行了聲明,而我們在實現時,就需要實現接口聲明的所有方法。除了這個典型的用法以外,我們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意以下的幾點:
1、覆蓋的方法的標誌必須要和被覆蓋的方法的標誌完全匹配,才能達到覆蓋的效果;
2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;
3、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類;
4、被覆蓋的方法不能為private,否則在其子類中只是新定義了一個方法,並沒有對其進行覆蓋。

17.什麼是java序列化,如何實現java序列化?或者請解釋Serializable接口的作用?

我們有時候將一個java對象變成字節流的形式傳出去或者從一個字節流中恢復成一個java對象,例如,要將java對象存儲到硬碟或者傳送給網絡上的其他計算機,這個過程我們可以自己寫代碼去把一個java對象變成某個格式的字節流再傳輸。
​
但是,jre本身就提供了這種支持,我們可以調用OutputStream的writeObject方法來做,如果要讓java幫我們做,要被傳輸的對象必須實現serializable接口,這樣,javac編譯時就會進行特殊處理,編譯的類才可以被writeObject方法操作,這就是所謂的序列化。需要被序列化的類必須實現Serializable接口,該接口是一個mini接口,其中沒有需要實現方法,implements Serializable只是為了標註該對象是可被序列化的。
​
例如,在web開發中,如果對象被保存在了Session中,tomcat在重啟時要把Session對象序列化到硬碟,這個對象就必須實現Serializable接口。如果對象要經過分布式系統進行網絡傳輸,被傳輸的對象就必須實現Serializable接口。
  • 字符串相關

18.String 為什麼是不可變的?

String 類中使用 `final` 關鍵字字符數組保存字符串。
​
String源碼:
// String.java
private final char[] value;
​
並且它是在堆中的字符串常量池中的,所以不可變。
​
StringBuilder 與 StringBuffer為什麼是可變的?
StringBuilder 與 StringBuffer 都繼承自 abstractStringBuilder 類,在 AbstractStringBuilder 中也是使用字符數組保存字符串 `char[] value` ,但是沒有用 `final` 關鍵字修飾。
源碼:
// AbstractStringBuilder.java
char[] value;
所以這兩種對象都是可變的。

19.String s = new String("xyz") 會創建幾個對象?

兩個。你new一個,在堆中創建了一個對象。
還有一個在字符串常量池中的字符串對象,它指向了一個字節數組。字節數組會把"xyz"轉化為相對應的ascii碼存儲在字節數組裡面。

20.說說你對字符串常量池的理解?

1.從jdk1.7開始,字符串常量池在堆當中。
​
2.字符串底層就有一個字節數組。名叫value。字符串常量池中的對象保存的就是byte[]字節數組的地址值。指向了字節數組。但是字符串對象自己也有一個地址。
​
3.jvm在幫你創建字符串abc的時候,其實是把它化成一個字節數組,再把字節數組的地址保存在字符串常量池中的字符串對象的地址中,再把字符串對象的地址賦給你創建的堆中的字符串引用。也就是說這個引用是先指向了字符串常量池中的字符串對象,字符串對象再指向字節數組,然後獲取值。
​
4.如果再創建一個字符串的話,也是指向同一個內存地址。但是值不同。
​
5.所有的String都指向一個地址。除非你去new一個,那就是不同的。
若String s1 = 「hello1」,同時聲明String s2 = s1,則s1和s2現在指向同一個地址,該地址指向字符串內容hello1
若在說明1的基礎上,再聲明s1 = 「hello1」,則同樣s1和s2指向同一個地址,該地址指向字符串內容內容hello1
若在說明1的基礎上,再聲明s1 = 「hello2」,則出現了變化,s1和s2的地址不再相同
若現在重新聲明String s2 = new String(s1),則說明s1和s2現在不同(s1==s2為false),但是所指向的內容是一致的,也就是說它們再堆內存中的地址是不一樣的,但是它們都指向了相同的字節數組
​
總結:因為String類是不可變的(imutable),當修改一個字符串時,我們不是在原來字符串的基礎上進行修改,而是申請一個新的地址空間,並將內容寫在新的空間裡。

21.String、StringBuffer、StringBuilder 的區別?

Java 平台提供了兩種類型的字符串:String 和 StringBuffer/StringBuilder,它們可以儲存和操作字符串。
​
String:只讀字符串,也就意味著 String 引用的字符串內容是不能被改變的。StringBuffer/StringBuilder 類,表示的字符串對象可以直接進行修改。每次對 String 類型進行改變的時候,都會生成一個新的 String 對象,然後將指針指向新的 String 對象。
​
StringBuilder:StringBuilder 是 Java 5 中引入的,它和 StringBuffer 的方法完全相同,區別在於它是在單線程環境下使用的,因為它的所有方面都沒有被 `synchronized` 修飾,因此它的效率也比 StringBuffer 要高。
​
StringBuffer:StringBuffer 每次都會對 StringBuffer 對象本身進行操作,而不是生成新的對象並改變對象引用。
相同情況下使用 StirngBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風險。
​
對於三者使用的總結:
操作少量的數據 = String 。這個也是實際編碼較為經常使用的方式。
單線程操作字符串緩衝區下操作大量數據 = StringBuilder 。甚至有時,我們為了避免每個線程重複創建 StringBuilder 對象,會通過 ThreadLocal + StringBuilder 的方式,進行對 StringBuilder 的重用。
多線程操作字符串緩衝區下操作大量數據 = StringBuffer。實際場景下,我們基本不太會出現,多線程操作同一個 StringBuffer 對象。
  • 關鍵字相關

22.談談你對this關鍵字的理解?

this關鍵字是存放在java棧幀中局部變量表變量槽的索引0的位置。它指的是一個方法或者變量的引用,通常指的是當前方法或者變量。一個對象去調用另一個方法,或者一個對象去調用一個變量,就是把指針指向了這個方法或者變量所處的局部變量表中的this指針的位置。也就是索引為0的位置。隨後這個方法就進棧。
​
this的三種用法
1.調用屬性:this可以調用本類中的任何成員變量
2.調用方法(可省略):this調用本類中的成員方法(在main方法裡面沒有辦法通過this調用)
3.調用構造方法:this調用構造方法只能在本構造方法中調用另一個構造方法;this 調用構造方法必須寫在第一行

23.談談你對super關鍵字的理解?

super可以理解為是指向自己超(父)類對象的一個指針,而這個超類指的是離自己最近的一個父類。
​
super的三種用法:
1.在子類的成員方法中,訪問父類的成員變量。
2.在子類的成員方法中,訪問父類的成員方法。
3.在子類的構造方法中,訪問父類的構造方法

24.那你知道this和super有什麼區別嗎?

this()和super()都指的是對象,所以,均不可以在static環境中使用。包括:static變量,static方法,static語句塊。
super()和this()類似,區別是,super()在子類中調用父類的構造方法,this()在本類內調用本類的其它構造方法。
從本質上講,this是一個指向本對象的指針, 然而super是一個Java關鍵字。

25.談談你對static關鍵字的理解?

只要是用了static關鍵字的變量,就不再屬於對象,是屬於類的。共享。
​
被static關鍵字修飾的變量,隨著類加載的出現而出現。
它在類加載過程的時候在連結階段的準備階段為類的靜態變量分配內存,並將其初始值轉化為默認值0或者null。在初始化階段為類的靜態變量賦予正確的初始值,就是你所定義的那個初始值
​
它優先於對象出現,所以在靜態環境中不可以訪問非靜態變量或者方法。
如果你的代碼嘗試不用實例來訪問非 `static` 的變量,編譯器會報錯,因為這些變量還沒有被創建出來,還沒有跟任何實例關聯上。

26.談談你對final關鍵字的理解?

final關鍵字代表最終、不可改變的的意思。
常見四種用法:
1.可以用來修飾一個類
2.可以用來修飾一個方法
3.可以用來修飾一個局部變量
4.還可以用來修飾一個成員變量
​
final不能和abstract同時使用。因為矛盾。
abstract必須有子類來繼承重寫方法,否則類沒有意義。但是final修飾的類不能有子類,矛盾。
就跟static和this矛盾一樣。
  • 哈希算法

27.你知道在Java中都有哪裡用到了哈希算法嗎?

1.HashMap.hash(),側重點是速度

2.Object.hashCode(),直接獲取內存地址

3.Integer.hashCode(),直接返回的int類型的Value

4.String.hashCode(),根據字符串內容生成hashCode,字符串內容一樣則hashCode也相同

  • 拷貝相關

28.Java中有多少種拷貝類型?分別說一下?

淺拷貝:淺拷貝只是複製了對象的引用地址,兩個對象指向同一個內存地址,所以修改其中任意的值,另一個值都會隨之變化。僅僅只是複製引用地址,而不是新建一個內存。
在Java語言中,通過覆蓋Object類的clone()方法可以實現淺克隆。
​
深拷貝:深拷貝是將對象及值複製過來,兩個對象修改其中任意的值另一個值不會改變。新建了一個新的內存
最重要的是將引用類型成員變量複製出來,相當於在內存中開闢了一塊新的地址了。新地址裡面的值和舊的地址裡面的值一樣。但是因為是在新的地址裡面操作了所以我們無論怎麼操作都不會改變舊的地址裡面的東西。兩個地址是完全獨立的。
​
在Java語言中,如果需要實現深克隆,可以通過覆蓋Object類的clone()方法實現,也可以通過序列化(Serialization)等方式來實現。

29.那你碰到過多引用拷貝嗎?知道怎麼解決嗎?

解決多引用拷貝的方式:
如果引用類型裡面還包含很多引用類型,或者內層引用類型的類裡面又包含引用類型,使用clone方法就會很麻煩。這時我們可以用序列化的方式來實現對象的深克隆。
序列化就是將對象寫到流的過程,寫到流中的對象是原有對象的一個拷貝,而原對象仍然存在於內存中。通過序列化實現的拷貝不僅可以複製對象本身,而且可以複製其引用的成員對象,因此通過序列化將對象寫到一個流中,再從流里將其讀出來,可以實現深克隆。需要注意的是能夠實現序列化的對象其類必須實現Serializable接口,否則無法實現序列化操作。
Java語言提供的Cloneable接口和Serializable接口的代碼非常簡單,它們都是空接口,這種空接口也稱為標識接口,標識接口中沒有任何方法的定義,其作用是告訴JRE這些接口的實現類是否具有某個功能,如是否支持克隆、是否支持序列化等。
  • 接口相關

30.你平時是怎麼使用接口的?談談你的理解?

1.接口沒有靜態代碼塊或者構造方法。
2.一個類的直接父類是唯一的,但是一個類可以實現多個接口。
3.一個類同時實現了兩個接口,兩個接口的方法重名了,那麼只需覆蓋重寫一次就好。
4.如果實現類沒有覆蓋重寫所有接口中的所有方法,那麼實現類就必須是一個抽象類。必須要有子類繼承這個實現類重寫完抽象方法這個接口體系才合法。
5.如果實現類所實現的多個接口中存在重複的默認方法,那麼實現類一定要對衝突的默認方法進行重寫。
6.繼承和實現的優先級問題:當一個類,既繼承一個父類,又實現若干個接口時,父類中的成員方法與接口中的默認方法重名,子類就近選擇執 行父類的成員方法。
​
7.接口的多繼承:一個接口能繼承另一個或者多個接口,這和類之間的繼承比較相似。接口的繼承使用 extends 關鍵字,子接口繼承父接口的方法。如果父接口中的默認方法有重名的,那么子接口需要重寫一次。而且要帶著default關鍵字。
也就是說,這個接口無法繼承使用它們父接口中的同名默認方法,因為衝突了。
但是如果不是默認方法,是普通方法,那麼繼承誰的都行。因為都是一樣的,實現的也是一樣的功能。
但是默認方法不行,因為默認方法是相當於在接口中就對方法進行了實現。這樣會導致衝突。

31.那聽你這麼說,接口的實現類的方法返回值類型是什麼?

返回值類型可以是接口、也可以是接口的實現類引用、或者直接new一個實現類對象也行。

32.方法的參數可以是接口嗎?

當然不行。如果方法形參類型是接口的話,傳的參必須是其實現類或者new,不然怎麼能叫引用呢。參數都是引用。
​
但是如果形參類型是類的話,形參可以是這個類的子類或者直接new一個子類。因為是繼承。參數是引用,只要能指向對象就行。

33.接口的返回值類型可否是另一個接口類型?

可以。一個接口裡可以讓方法的返回值類型是其他接口的類型。其實就是玩多態。

34.接口引用調用實現類方法?

只能調用實現類重寫的。實現類自己的不能調用。
  • 抽象類

35.抽象類使用規則

繼承抽象類的子類必須重寫父類所有的抽象方法。否則,該子類也必須聲明為抽象類。最終,必須有子類能夠實現完剩下的全部抽象方法,否則,從最初的父類到最終的子類都不能創建對象,失去意義。
​
如果A是抽象類,B繼承A,必須得繼承全部的。否則B也是個抽象類,不能創建對象。C去繼承B的話,得繼承完剩下的B沒繼承A的,如果方法B已經繼承,可以重寫,但是要等到C重寫了所有沒實現的抽象類,才可以創建對象,去調用方法來使用。否則,C依然是個抽象類。

36.抽象類注意事項?

抽象類不能創建對象,如果創建,編譯無法通過而報錯。只能創建其非抽象子類的對象。
抽象類中,可以有構造方法,是供子類創建對象時,初始化父類成員使用的。
抽象類中,不一定包含抽象方法,但是有抽象方法的類必定是抽象類。

37.abstractclass和interface語法上有什麼區別?

1.抽象類可以有構造方法,接口中不能有構造方法。
2.抽象類中可以有普通成員變量,接口中沒有普通成員變量
3.抽象類中可以包含非抽象的普通方法,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法。
4. 抽象類中可以包含靜態方法,接口中不能包含靜態方法。
5. 抽象類和接口中都可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型可以任意,但接口中定義的變量只能是publicstatic final類型,並且默認即為publicstatic final類型。
6.一個類可以實現多個接口,但只能繼承一個抽象類。

38.接口是否可繼承接口?抽象類是否可繼承具體類(concreteclass)?抽象類中是否可以有靜態的main方法?

接口可以繼承接口。抽象類可以實現(implements)接口,抽象類可以繼承具體類。抽象類中可以有靜態的main方法。
只要記住:抽象類與普通類的唯一區別就是不能創建實例對象和允許有abstract方法。
  • 包裝類

39.什麼是自動拆裝箱?

自動裝箱和拆箱,就是基本類型和引用類型之間的轉換。

40.為什麼要轉換?

因為不能直接地向集合( Collection )中放入原始類型值,因為集合只接收對象。
通常這種情況下你的做法是,將這些原始類型的值轉換成對象,然後將這些轉換的對象放入集合中。使用 Integer、Double、Boolean 等這些類,我們可以將原始類型值轉換成對應的對象,但是從某些程度可能使得代碼不是那麼簡潔精煉。
為了讓代碼簡練,Java5 引入了具有在原始類型和對象類型自動轉換的裝箱和拆箱機制。
  • 泛型

41.你平時是如何使用泛型的?

1.使用含有泛型的類:
在類上標註泛型代表我們還不知道是什麼類型。等到測試類創建對象的時候確定泛型的類型。到時候類和方法的類型會變成相對應的類型。
​
2.使用含有泛型的方法:
在調用方法的時候確定泛型的類型。
​
3.使用含有泛型的接口:
第一種方式,創建泛型接口,接口上未確認泛型是什麼類型。在實現類上決定泛型的類型。並且之後的所有實現方法都會默認是這個類型。
第二種方式,接口已經確認了泛型類型。實現類就得跟著用什麼類型。如果一個子接口繼承了父接口,那麼父接口如果確定了泛型類型,子接口也得跟著是什麼類型。
​
4.使用泛型通配符
?:代表任意的數據類型使用方式:
但它不能創建對象使用,只能作為方法的參數使用。
  • 異常

42.Exeception和Error區別?

Exception 和 Error 都是繼承了 Throwable 類,在 Java 中只有 Throwable 類型的實例才可以被拋出(throw)或者捕獲(catch),它是異常處理機制的基本組成類型。
​
Exception 和 Error 體現了 Java 平台設計者對不同異常情況的分類。Exception 是程序正常運行中,可以預料的意外情況,可能並且應該被捕獲,進行相應處理。
​
Error 是指在正常情況下,不大可能出現的情況,絕大部分的 Error 都會導致程序(比如 JVM 自身)處於非正常的、不可恢復狀態。既然是非正常情況,所以不便於也不需要捕獲,常見的比如 OutOfMemoryError 之類,都是 Error 的子類。
​
Exception 又分為可檢查(checked)異常和不可檢查(unchecked)異常:
可檢查異常在原始碼里必須顯式地進行捕獲處理,這是編譯期檢查的一部分。前面我介紹的不可查的 Error,是 Throwable 不是 Exception。
不檢查異常就是所謂的運行時異常,類似 NullPointerException、ArrayIndexOutOfBoundsException 之類,通常是可以編碼避免的邏輯錯誤,具體根據需要來判斷是否需要捕獲,並不會在編譯期強制要求。

43.那你知道異常有幾種處理方式嗎?

1.throws
交給別人處理。步驟:
只要我們在方法裡面throw拋出一個異常,如果是RuntimeException或者其子類,就會默認給jvm接盤處理。jvm會中斷程序,列印到控制台上。是jvm進行中斷處理的
​
否則,我們要在方法體throws上聲明,然後給下一個接盤者。
​
如果是在主方法調用,因為主方法調用了它,所以主方法要麼處理異常,要麼就繼續在主方法名上throws找人接盤處理,最後會讓jvm來處理。
​
所以,只要throw了,至少要在異常的方法名上throws,要麼自己處理,要麼找人接盤。
​
2.try catch finally
自己處理異常,方式:
多個異常多次拋出多次處理
多個異常一次捕獲,一次處理
多個異常一次拋出多次處理
運行時異常可以不用拋出和捕獲處理,交給jvm

44.說說Throwable類怎麼用吧?

Throwable類中有3個異常處理方法
1.getMessage():返回throwable的簡簡訊息
2.toString():返回throwable的詳細消息字符串
3.printStackTrace():jvm列印異常對象,默認此方法,異常信息最全面

45.你最常見到的是Java中的什麼異常?

那必須得是運行時異常啊:
ClassCastException(類轉換異常)
IndexOutOfBoundsException(數組越界異常)
NullPointerException(空指針異常)
ArrayStoreException(數據存儲異常,操作數組時類型不一致)
BufferOverflowException(還有IO操作的,緩衝溢出異常)
  • 反射機制

46.什麼是反射機制?

Class類對象階段是在內存中的。已經被編譯成字節碼加載進虛擬機內存。這個時候對於我們用戶來說是看不到類的一些信息的,那我們如果又想看到這些類的信息,就可以通過反射機制獲取,或者說當你無法確定到底傳入的類是什麼樣子的時候,要通用兼容所有可能的類,就需要用反射機制動態去調用類的屬性和行為。

47.那怎麼使用反射呢?

1.使用反射獲取字節碼Class對象:
Class.forName("全類名")
Class.forName("全類名")
對象.getClass()
​
2.使用Class對象:
通過Field類獲取成員變量
通過Constructor類獲取構造方法
通過Method類獲取成員方法

48.你反射這麼熟悉,那一般在哪些場景用到它啊?

1.逆向代碼 ,例如反編譯
​
2.與註解相結合的框架
​
3.動態獲取信息,動態代理(AOP中的動態代理:實現了接口的使用JDK的動態代理,沒有實現接口的使用CGlib動態代理)使用反射

49.聽你說的這麼多,那它就沒有缺點嗎?

有的。它的性能是一個問題,反射相當於一系列解釋操作,通知jvm要做的事情,所以性能比直接的java代碼要慢很多。
  • JDK1.8新特性

50.你知道JDK1.8有哪些新特性嗎?

1.函數式接口
函數式接口指的是有且只有一個抽象方法的接口,並且接口中可以包含其它的方法。
我們可以使用@FunctionalInterface註解去檢測一個接口是否是一個函數式接口
常用的函數式接口有:
Supplier接口:它是一個生產型接口,當你指定接口是什麼類型時,接口的get方法就會生產什麼類型的數據
Function接口:這個接口用來根據一個類型的數據去獲取另一個類型的數據,前者稱為前置條件,後者稱為後置條件。
這個接口中最主要的抽象方法為:R apply(T t),去根據類型T的參數獲取類型R的結果。
使用場景有很多,比如:將String類型轉化為Integer類型。

2.Stream流:
Stream流屬於管道流,只能波消費(使用)一次
第一個Stream流調用完畢方法,數據就會流轉到下一個Stream上而這時第一個Stream流已經使用完畢,就會關閉了所以第一個Stream流就不能再調用方法了。
常用方法:
forEach():用來遍歷流中的數據,是一個終結方法。遍歷之後就不能再調用Stream流中的其它方法了。
filter():它可以傳遞lambda表達式,對數據進行過濾。
map()::該接口需要一個Function函數式接口參數,可以將當前流中的T數據轉換為另一種R類型的流。
skip():如果希望跳過前幾個元素,可以使用skip方法獲取一個截取之後的新流。
concat():如果有兩個流希望合併成一個流,那麼使用Stream接口的靜態方法concat就可以
​
3.Lambda表達式:
lambda表達式的標準格式由三部分組成:
1.箭頭 2.參數 3.代碼
格式: (參數列表) -> {核心代碼};
格式說明:
() :接口中抽象方法的參數列表,沒有參數的時候就空著,有參數的話就正常寫出參數,多個參數用逗號分割
-> :傳遞的意思,把參數傳遞給方法體{}
{} :重寫接口的抽象方法的方法體
​
對於Lambda表達式來說,真正重要的是參數,方法體和返回值。其他的,都可以省略。

將最重要的《25大專題Java面試專題》筆記拿出來,免費分享給大家需要獲取的小夥伴可以直接轉發+關注後私信(學習)即可獲取到!

JavaOOP面試題

Java集合/泛型面試題

Java異常面試題

Java中的IO與NIO面試題

因為篇幅原因,大部分的內容就不給大家一一展示了,需要獲取的小夥伴可以直接轉發+關注後私信(學習)即可獲取到!

學習資料大禮包:

涵蓋面試準備、項目經驗、簡歷編寫、源碼學習、算法準備、面試資源等內容



關鍵字: