超全面!阿里巴巴最新發(fā)布23年秋招200道Java面試題(含答案)
馬上過34歲生日了,和大家聊聊最近的情況
半年前還在迷茫該學什么,怎樣才能走出現(xiàn)在的困境,半年后已經(jīng)成功上岸阿里,感謝在這期間幫助我的每一個人。
面試中總結了200道經(jīng)典的Java面試題,里面包含面試要回答的知識重點,并且我根據(jù)知識類型進行了分類,可以說非常全面了~
因為篇幅原因,大部分的內(nèi)容就不給大家一一展示了,需要獲取的小伙伴可以直接轉發(fā) 關注后私信(學習)即可獲取到!
java平臺相關
1、JDK、JRE、JVM 分別是什么關系? 2、為什么 Java 被稱作是“平臺無關的編程語言”? 3、Java 和 C 的區(qū)別? 4、什么是字節(jié)碼?采用字節(jié)碼的最大好處是什么? 5、Java運行的過程? 6、Java是動態(tài)類型語言還是靜態(tài)類型語言?
面向對象
7.什么是面向對象? 8.請說說面向對象的特征?封裝、繼承、多態(tài)分別說一下,以及它們的好處? 9.多態(tài)為什么要轉型? 10.說一下權限修飾符的使用權限?
語言基礎
- 基本數(shù)據(jù)類型和引用類型
11.Java 中的幾種基本數(shù)據(jù)類型是什么?各自占用多少字節(jié)? 12.char 型變量中能不能存貯一個中文漢字?為什么? 13.什么是引用類型? 14.什么是值傳遞和引用傳遞? 15.屬性(字段)和變量的區(qū)別? 16.什么是重載和重寫?Overload(重載)和override(重寫)的區(qū)別? 17.什么是java序列化,如何實現(xiàn)java序列化?或者請解釋serializable接口的作用?
- 字符串相關
18.String 為什么是不可變的? 19.String s = new String("xyz") 會創(chuàng)建幾個對象? 20.說說你對字符串常量池的理解? 21.String、StringBuffer、StringBuilder 的區(qū)別? 22.談談你對this關鍵字的理解? 23.談談你對super關鍵字的理解? 24.那你知道this和super有什么區(qū)別嗎? 25.談談你對static關鍵字的理解? 26.談談你對final關鍵字的理解?
27.你知道在Java中都有哪里用到了哈希 嗎?
- 拷貝相關
28.Java中有多少種拷貝類型?分別說一下? 29.那你碰到過多引用拷貝嗎?知道怎么解決嗎?
- 接口相關
30.你平時是怎么使用接口的?談談你的理解? 31.那聽你這么說,接口的實現(xiàn)類的方法返回值類型是什么? 32.方法的參數(shù)可以是接口嗎? 33.接口的返回值類型可否是另一個接口類型?
- 抽象類
34.接口引用調用實現(xiàn)類方法? 35.抽象類使用規(guī)則 36.抽象類注意事項? 37.Abstractclass和interface語法上有什么區(qū)別? 38.接口是否可繼承接口?抽象類是否可繼承具體類(concreteclass)?抽象類中是否可以有靜態(tài)的main方法?
- 包裝類
39.什么是自動拆裝箱? 40.為什么要轉換?
- 泛型
41.你平時是如何使用泛型的?
- 異常
42.Exeception和Error區(qū)別? 43.那你知道異常有幾種處理方式嗎? 44.說說Throwable類怎么用吧? 45.你最常見到的是Java中的什么異常?
- 反射機制
46.什么是反射機制? 47.那怎么使用反射呢? 48.你反射這么熟悉,那一般在哪些場景用到它??? 49.聽你說的這么多,那它就沒有缺點嗎?
- JDK1.8新特性
50.你知道JDK1.8有哪些新特性嗎?
以下是答案:
Java平臺相關
1、JDK、JRE、JVM 分別是什么關系?
JDK 即為 Java 開發(fā)工具包,包含編寫 Java 程序所必須的編譯、運行等開發(fā)工具以及 JRE。開發(fā)工具如:用于編譯 Java 程序的 javac 命令。用于啟動 JVM 運行 Java 程序的 Java 命令。用于生成文檔的 Javadoc 命令。用于打包的 jar 命令等等。
2、為什么 Java 被稱作是“平臺無關的編程語言”?
Java 虛擬機是一個可以執(zhí)行 Java 字節(jié)碼的虛擬機進程。Java 源文件( `.java` )被編譯成能被 Java 虛擬機執(zhí)行的字節(jié)碼文件( `.class` )。Java 被設計成允許應用程序可以運行在任意的平臺,而不需要程序員為每一個平臺單獨重寫或者是重新編譯。Java 虛擬機讓這個變?yōu)榭赡埽驗樗赖讓佑布脚_的指令長度和其他特性。
3、Java 和 C 的區(qū)別?
都是面向對象的語言,都支持封裝、繼承和多態(tài)。Java 不提供指針來直接訪問內(nèi)存,程序內(nèi)存更加安全。Java 的類是單繼承的,C 支持多重繼承;雖然 Java 的類不可以多繼承,但是接口可以多繼承。Java 有自動內(nèi)存管理機制,不需要程序員手動釋放無用內(nèi)存。
4、什么是字節(jié)碼?采用字節(jié)碼的最大好處是什么?
Java 中引入了虛擬機的概念,即在機器和編譯程序之間加入了一層抽象的虛擬的機器。這臺虛擬的機器在任何平臺上都提供給編譯程序一個的共同的接口。編譯程序只需要面向虛擬機,生成虛擬機能夠理解的代碼,然后由解釋器來將虛擬機代碼轉換為特定系統(tǒng)的機器碼執(zhí)行。在 Java 中,這種供虛擬機理解的代碼叫做字節(jié)碼(即擴展名為 `.class` 的文件),它不面向任何特定的處理器,只面向虛擬機。每一種平臺的解釋器是不同的,但是實現(xiàn)的虛擬機是相同的。Java 源程序經(jīng)過編譯器編譯后變成字節(jié)碼,字節(jié)碼由虛擬機解釋執(zhí)行,虛擬機將每一條要執(zhí)行的字節(jié)碼送給解釋器,解釋器將其翻譯成特定機器上的機器碼,然后在特定的機器上運行。這也就是解釋了 Java 的編譯與解釋并存的特點。采用字節(jié)碼的好處:Java 語言通過字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語言執(zhí)行效率低的問題,同時又保留了解釋型語言可移植的特點。所以 Java 程序運行時比較高效,而且,由于字節(jié)碼并不專對一種特定的機器,因此,Java程序無須重新編譯便可在多種不同的計算機上運行。
5、Java運行的過程?
Java 源代碼=> 編譯器 => JVM 可執(zhí)行的 Java 字節(jié)碼(即虛擬指令)=> JVM => JVM 中解釋器 => 機器可執(zhí)行的二進制機器碼 => 程序運行
6、Java是動態(tài)類型語言還是靜態(tài)類型語言?
動態(tài)類型語言和靜態(tài)類型語言兩者的卻別就在于對類型的檢查是在編譯期還是在運行期,滿足前者就是靜態(tài)類型語言,反之則是動態(tài)類型語言。直白來說靜態(tài)語言是判斷變量自身的類型信息;動態(tài)類型語言是判斷變量值的類型信息,變量設有類型信息,變量值才有類型信息,這是動態(tài)語言的一個重要特征。?Java是靜態(tài)類型語言(盡管lambda表達式為其增加了動態(tài)特性),js,python是動態(tài)類型語言。
面向對象
7.什么是面向對象?
面向對象是一種思想,世間萬物都可以看做一個對象,這里只討論面向對象編程(OOP),Java 是一個支持并發(fā)、基于類和面向對象的計算機高級編程語言。面向對象軟件開發(fā)具有以下優(yōu)點:代碼開發(fā)模塊化,更易維護和修改。代碼復用性強。增加代碼的可讀性。
8.請說說面向對象的特征?封裝、繼承、多態(tài)分別說一下,以及它們的好處?
1.封裝:封裝,給對象提供了隱藏內(nèi)部特性和行為的能力。對象提供一些能被其他對象訪問的方法來改變它內(nèi)部的數(shù)據(jù)。在 Java 當中,有 4 種修飾符: `default`、`public`、`private` 和 `protected` 。每一種修飾符給其他的位于同一個包或者不同包下面對象賦予了不同的訪問權限。?使用封裝的一些好處: 通過隱藏對象的屬性來保護對象內(nèi)部的狀態(tài)。 提高了代碼的可用性和可維護性,因為對象的行為可以被單獨的改變或者是擴展。 禁止對象之間的不良交互提高模塊化。?2.繼承:繼承,給對象提供了從基類獲取字段和方法的能力。繼承提供了代碼的重用行,也可以在不修改類的情況下給現(xiàn)存的類添加新特性。?3.多態(tài):多態(tài),是編程語言給不同的底層數(shù)據(jù)類型做相同的接口展示的一種能力。一個多態(tài)類型上的操作,可以應用到其他類型的值上面。多態(tài)中,父類作為形參的方法和子類作為形參的方法都是一樣的。形參父類類型可以接收子類對象。這是多態(tài)的特性。?重要特性:轉型向上轉型:父類引用指向子類對象。相當于子類對象賦給父類引用。這樣子,是默認的。子類的方法可以重寫父類的方法。但是,向上轉型的弊端就是只能使用父類有的方法,一旦向上轉型就不能調用子類特有的方法。所以需要向下轉型還原。?向下轉型:其實是一個還原的步驟。子類引用指向父類的一個引用。這個要強轉類型。因為我們父類不能去拿子類已經(jīng)有的東西。所以必須把父類轉化為和子類一個類型。
9.多態(tài)為什么要轉型?
當使用多態(tài)方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤。也就是說,不能調用子類擁有,而父類沒有的方法。編譯都錯誤,更別說運行了。這也是多態(tài)給我們帶來的一點"小麻煩”。所以,想要調用子類特有的方法,必須做向下轉型。
10.說一下權限修飾符的使用權限?
同一個類:四個都能訪問。?同一個包不同類:public、protected和defaut都能訪問。private不能訪問?不同包但是B類是A類的子類:首先,必須導包。如果要用B類繼承A類,必須先導入A類所在的包。public和protect能訪問。default不能訪問。private也不能。?不同包非子類:一點關系沒有。兩個類是陌生關系。不是一個包里的也沒有繼承(實現(xiàn))關系。只有public可以訪問。其他都不行。
語言基礎
- 基本數(shù)據(jù)類型和引用類型
11.Java 中的幾種基本數(shù)據(jù)類型是什么?各自占用多少字節(jié)?
基本數(shù)據(jù)類型如下:byte 1字節(jié)boolean false/true(理論上占用1bit,1/8字節(jié),實際處理按1byte處理)char 2字節(jié)(C語言中是1字節(jié))short 2字節(jié)int 4字節(jié)long 8字節(jié)float 4字節(jié)double 8字節(jié)
12.char 型變量中能不能存貯一個中文漢字?為什么?
在 Java 語言中,char 類型占 2 個字節(jié),而且 Java 默認采用 Unicode 編碼,一個 Unicode 碼是 16 位,所以一個 Unicode 碼占兩個字節(jié)。Java 中無論漢字還是英文字母,都是用 Unicode 編碼來表示的。所以,在 Java 中,char 類型變量可以存儲一個中文漢字。
13.什么是引用類型?
引用類型聲明的變量是指該變量在內(nèi)存中實際存儲的是一個引用地址,實體在堆中。引用類型包括類、接口、數(shù)組等。特別注意,String 是引用類型不是基本類型。
14.什么是值傳遞和引用傳遞?
值傳遞,是對基本型變量而言的,傳遞的是該變量的一個副本,改變副本不影響原變量。引用傳遞,一般是對于對象型變量而言的,傳遞的是該對象地址的一個副本,并不是原對象本身。一般認為,Java 內(nèi)的傳遞都是值傳遞,Java 中實例對象的傳遞是引用傳遞。
15.屬性(字段)和變量的區(qū)別?
字段是成員變量,是在類中聲明的變量。變量可以分為局部變量和成員變量。成員變量就是字段也叫做屬性。所以字段就是屬性就是成員變量。
16.什么是重載和重寫?Overload(重載)和Override(重寫)的區(qū)別?
重載:Overload就是重載的意思。?重載Overload表示同一個類中可以有多個名稱相同的方法,但這些方法的參數(shù)列表各不相同(即參數(shù)個數(shù)或類型不同)。Overload對我們來說可能比較熟悉,可以翻譯為重載,它是指我們可以定義一些名稱相同的方法,通過定義不同的輸入?yún)?shù)來區(qū)分這些方法,然后再調用時,JVM就會根據(jù)不同的參數(shù)樣式,來選擇合適的方法執(zhí)行。在使用重載要注意以下的幾點:1、在使用重載時只能通過不同的參數(shù)樣式。例如,不同的參數(shù)類型,不同的參數(shù)個數(shù),不同的參數(shù)順序(當然,同一方法內(nèi)的幾個參數(shù)類型必須不一樣,例如可以是fun(int,float),但是不能為fun(int,int));2、不能通過訪問權限、返回類型、拋出的異常進行重載;3、方法的異常類型和數(shù)目不會對重載造成影響;4、對于繼承來說,如果某一方法在父類中是訪問權限是priavte,那么就不能在子類對其進行重載,如果定義的話,也只是定義了一個新方法,而不會達到重載的效果。?重寫:Override是覆蓋的意思,也就是重寫。?重寫Override表示子類中的方法可以與父類中的某個方法的名稱和參數(shù)完全相同,通過子類創(chuàng)建的實例對象調用這個方法時,將調用子類中的定義方法,這相當于把父類中定義的那個完全相同的方法給覆蓋了,這也是面向對象編程的多態(tài)性的一種表現(xiàn)。子類覆蓋父類的方法時,只能比父類拋出更少的異常,或者是拋出父類拋出的異常的子異常,因為子類可以解決父類的一些問題,不能比父類有更多的問題。子類方法的訪問權限只能比父類的更大,不能更小。如果父類的方法是private類型,那么,子類則不存在覆蓋的限制,相當于子類中增加了一個全新的方法。?override可以翻譯為覆蓋,從字面就可以知道,它是覆蓋了一個方法并且對其重寫,以求達到不同的作用。對我們來說最熟悉的覆蓋就是對接口方法的實現(xiàn),在接口中一般只是對方法進行了聲明,而我們在實現(xiàn)時,就需要實現(xiàn)接口聲明的所有方法。除了這個典型的用法以外,我們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意以下的幾點:1、覆蓋的方法的標志必須要和被覆蓋的方法的標志完全匹配,才能達到覆蓋的效果;2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;3、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類;4、被覆蓋的方法不能為private,否則在其子類中只是新定義了一個方法,并沒有對其進行覆蓋。
17.什么是java序列化,如何實現(xiàn)java序列化?或者請解釋Serializable接口的作用?
我們有時候將一個java對象變成字節(jié)流的形式傳出去或者從一個字節(jié)流中恢復成一個java對象,例如,要將java對象存儲到硬盤或者傳送給網(wǎng)絡上的其他計算機,這個過程我們可以自己寫代碼去把一個java對象變成某個格式的字節(jié)流再傳輸。?但是,jre本身就提供了這種支持,我們可以調用OutputStream的writeObject方法來做,如果要讓java幫我們做,要被傳輸?shù)膶ο蟊仨殞崿F(xiàn)serializable接口,這樣,javac編譯時就會進行特殊處理,編譯的類才可以被writeObject方法操作,這就是所謂的序列化。需要被序列化的類必須實現(xiàn)Serializable接口,該接口是一個mini接口,其中沒有需要實現(xiàn)方法,implements Serializable只是為了標注該對象是可被序列化的。?例如,在web開發(fā)中,如果對象被保存在了Session中,tomcat在重啟時要把Session對象序列化到硬盤,這個對象就必須實現(xiàn)Serializable接口。如果對象要經(jīng)過分布式系統(tǒng)進行網(wǎng)絡傳輸,被傳輸?shù)膶ο缶捅仨殞崿F(xiàn)Serializable接口。
- 字符串相關
18.String 為什么是不可變的?
String 類中使用 `final` 關鍵字字符數(shù)組保存字符串。?String源碼:// String.javaprivate final char[] value;?并且它是在堆中的字符串常量池中的,所以不可變。?StringBuilder 與 StringBuffer為什么是可變的?StringBuilder 與 StringBuffer 都繼承自 abstractStringBuilder 類,在 AbstractStringBuilder 中也是使用字符數(shù)組保存字符串 `char[] value` ,但是沒有用 `final` 關鍵字修飾。源碼:// AbstractStringBuilder.javachar[] value;所以這兩種對象都是可變的。
19.String s = new String("xyz") 會創(chuàng)建幾個對象?
兩個。你new一個,在堆中創(chuàng)建了一個對象。還有一個在字符串常量池中的字符串對象,它指向了一個字節(jié)數(shù)組。字節(jié)數(shù)組會把"xyz"轉化為相對應的ascii碼存儲在字節(jié)數(shù)組里面。
20.說說你對字符串常量池的理解?
1.從jdk1.7開始,字符串常量池在堆當中。?2.字符串底層就有一個字節(jié)數(shù)組。名叫value。字符串常量池中的對象保存的就是byte[]字節(jié)數(shù)組的地址值。指向了字節(jié)數(shù)組。但是字符串對象自己也有一個地址。?3.jvm在幫你創(chuàng)建字符串a(chǎn)bc的時候,其實是把它化成一個字節(jié)數(shù)組,再把字節(jié)數(shù)組的地址保存在字符串常量池中的字符串對象的地址中,再把字符串對象的地址賦給你創(chuàng)建的堆中的字符串引用。也就是說這個引用是先指向了字符串常量池中的字符串對象,字符串對象再指向字節(jié)數(shù)組,然后獲取值。?4.如果再創(chuàng)建一個字符串的話,也是指向同一個內(nèi)存地址。但是值不同。?5.所有的String都指向一個地址。除非你去new一個,那就是不同的。若String s1 = “hello1”,同時聲明String s2 = s1,則s1和s2現(xiàn)在指向同一個地址,該地址指向字符串內(nèi)容hello1若在說明1的基礎上,再聲明s1 = “hello1”,則同樣s1和s2指向同一個地址,該地址指向字符串內(nèi)容內(nèi)容hello1若在說明1的基礎上,再聲明s1 = “hello2”,則出現(xiàn)了變化,s1和s2的地址不再相同若現(xiàn)在重新聲明String s2 = new String(s1),則說明s1和s2現(xiàn)在不同(s1==s2為false),但是所指向的內(nèi)容是一致的,也就是說它們再堆內(nèi)存中的地址是不一樣的,但是它們都指向了相同的字節(jié)數(shù)組?總結:因為String類是不可變的(imutable),當修改一個字符串時,我們不是在原來字符串的基礎上進行修改,而是申請一個新的地址空間,并將內(nèi)容寫在新的空間里。
21.String、StringBuffer、StringBuilder 的區(qū)別?
Java 平臺提供了兩種類型的字符串:String 和 StringBuffer/StringBuilder,它們可以儲存和操作字符串。?String:只讀字符串,也就意味著 String 引用的字符串內(nèi)容是不能被改變的。StringBuffer/StringBuilder 類,表示的字符串對象可以直接進行修改。每次對 String 類型進行改變的時候,都會生成一個新的 String 對象,然后將指針指向新的 String 對象。?StringBuilder:StringBuilder 是 Java 5 中引入的,它和 StringBuffer 的方法完全相同,區(qū)別在于它是在單線程環(huán)境下使用的,因為它的所有方面都沒有被 `synchronized` 修飾,因此它的效率也比 StringBuffer 要高。?StringBuffer:StringBuffer 每次都會對 StringBuffer 對象本身進行操作,而不是生成新的對象并改變對象引用。相同情況下使用 StirngBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風險。?對于三者使用的總結:操作少量的數(shù)據(jù) = String 。這個也是實際編碼較為經(jīng)常使用的方式。單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) = StringBuilder 。甚至有時,我們?yōu)榱吮苊饷總€線程重復創(chuàng)建 StringBuilder 對象,會通過 ThreadLocal StringBuilder 的方式,進行對 StringBuilder 的重用。多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) = StringBuffer。實際場景下,我們基本不太會出現(xiàn),多線程操作同一個 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有什么區(qū)別嗎?
this()和super()都指的是對象,所以,均不可以在static環(huán)境中使用。包括:static變量,static方法,static語句塊。super()和this()類似,區(qū)別是,super()在子類中調用父類的構造方法,this()在本類內(nèi)調用本類的其它構造方法。從本質上講,this是一個指向本對象的指針, 然而super是一個Java關鍵字。
25.談談你對static關鍵字的理解?
只要是用了static關鍵字的變量,就不再屬于對象,是屬于類的。共享。?被static關鍵字修飾的變量,隨著類加載的出現(xiàn)而出現(xiàn)。它在類加載過程的時候在鏈接階段的準備階段為類的靜態(tài)變量分配內(nèi)存,并將其初始值轉化為默認值0或者null。在初始化階段為類的靜態(tài)變量賦予正確的初始值,就是你所定義的那個初始值?它優(yōu)先于對象出現(xiàn),所以在靜態(tài)環(huán)境中不可以訪問非靜態(tài)變量或者方法。如果你的代碼嘗試不用實例來訪問非 `static` 的變量,編譯器會報錯,因為這些變量還沒有被創(chuàng)建出來,還沒有跟任何實例關聯(lián)上。
26.談談你對final關鍵字的理解?
final關鍵字代表最終、不可改變的的意思。常見四種用法:1.可以用來修飾一個類2.可以用來修飾一個方法3.可以用來修飾一個局部變量4.還可以用來修飾一個成員變量?final不能和abstract同時使用。因為矛盾。abstract必須有子類來繼承重寫方法,否則類沒有意義。但是final修飾的類不能有子類,矛盾。就跟static和this矛盾一樣。
- 哈希算法
27.你知道在Java中都有哪里用到了哈希算法嗎?
1.HashMap.hash(),側重點是速度
2.Object.hashCode(),直接獲取內(nèi)存地址
3.Integer.hashCode(),直接返回的int類型的Value
4.String.hashCode(),根據(jù)字符串內(nèi)容生成hashCode,字符串內(nèi)容一樣則hashCode也相同
- 拷貝相關
28.Java中有多少種拷貝類型?分別說一下?
淺拷貝:淺拷貝只是復制了對象的引用地址,兩個對象指向同一個內(nèi)存地址,所以修改其中任意的值,另一個值都會隨之變化。僅僅只是復制引用地址,而不是新建一個內(nèi)存。在Java語言中,通過覆蓋Object類的clone()方法可以實現(xiàn)淺克隆。?深拷貝:深拷貝是將對象及值復制過來,兩個對象修改其中任意的值另一個值不會改變。新建了一個新的內(nèi)存最重要的是將引用類型成員變量復制出來,相當于在內(nèi)存中開辟了一塊新的地址了。新地址里面的值和舊的地址里面的值一樣。但是因為是在新的地址里面操作了所以我們無論怎么操作都不會改變舊的地址里面的東西。兩個地址是完全獨立的。?在Java語言中,如果需要實現(xiàn)深克隆,可以通過覆蓋Object類的clone()方法實現(xiàn),也可以通過序列化(Serialization)等方式來實現(xiàn)。
29.那你碰到過多引用拷貝嗎?知道怎么解決嗎?
解決多引用拷貝的方式:如果引用類型里面還包含很多引用類型,或者內(nèi)層引用類型的類里面又包含引用類型,使用clone方法就會很麻煩。這時我們可以用序列化的方式來實現(xiàn)對象的深克隆。序列化就是將對象寫到流的過程,寫到流中的對象是原有對象的一個拷貝,而原對象仍然存在于內(nèi)存中。通過序列化實現(xiàn)的拷貝不僅可以復制對象本身,而且可以復制其引用的成員對象,因此通過序列化將對象寫到一個流中,再從流里將其讀出來,可以實現(xiàn)深克隆。需要注意的是能夠實現(xiàn)序列化的對象其類必須實現(xiàn)Serializable接口,否則無法實現(xiàn)序列化操作。Java語言提供的Cloneable接口和Serializable接口的代碼非常簡單,它們都是空接口,這種空接口也稱為標識接口,標識接口中沒有任何方法的定義,其作用是告訴JRE這些接口的實現(xiàn)類是否具有某個功能,如是否支持克隆、是否支持序列化等。
- 接口相關
30.你平時是怎么使用接口的?談談你的理解?
1.接口沒有靜態(tài)代碼塊或者構造方法。2.一個類的直接父類是唯一的,但是一個類可以實現(xiàn)多個接口。3.一個類同時實現(xiàn)了兩個接口,兩個接口的方法重名了,那么只需覆蓋重寫一次就好。4.如果實現(xiàn)類沒有覆蓋重寫所有接口中的所有方法,那么實現(xiàn)類就必須是一個抽象類。必須要有子類繼承這個實現(xiàn)類重寫完抽象方法這個接口體系才合法。5.如果實現(xiàn)類所實現(xiàn)的多個接口中存在重復的默認方法,那么實現(xiàn)類一定要對沖突的默認方法進行重寫。6.繼承和實現(xiàn)的優(yōu)先級問題:當一個類,既繼承一個父類,又實現(xiàn)若干個接口時,父類中的成員方法與接口中的默認方法重名,子類就近選擇執(zhí) 行父類的成員方法。7.接口的多繼承:一個接口能繼承另一個或者多個接口,這和類之間的繼承比較相似。接口的繼承使用 extends 關鍵字,子接口繼承父接口的方法。如果父接口中的默認方法有重名的,那么子接口需要重寫一次。而且要帶著default關鍵字。也就是說,這個接口無法繼承使用它們父接口中的同名默認方法,因為沖突了。但是如果不是默認方法,是普通方法,那么繼承誰的都行。因為都是一樣的,實現(xiàn)的也是一樣的功能。但是默認方法不行,因為默認方法是相當于在接口中就對方法進行了實現(xiàn)。這樣會導致沖突。
31.那聽你這么說,接口的實現(xiàn)類的方法返回值類型是什么?
返回值類型可以是接口、也可以是接口的實現(xiàn)類引用、或者直接new一個實現(xiàn)類對象也行。
32.方法的參數(shù)可以是接口嗎?
當然不行。如果方法形參類型是接口的話,傳的參必須是其實現(xiàn)類或者new,不然怎么能叫引用呢。參數(shù)都是引用。?但是如果形參類型是類的話,形參可以是這個類的子類或者直接new一個子類。因為是繼承。參數(shù)是引用,只要能指向對象就行。
33.接口的返回值類型可否是另一個接口類型?
可以。一個接口里可以讓方法的返回值類型是其他接口的類型。其實就是玩多態(tài)。
34.接口引用調用實現(xiàn)類方法?
只能調用實現(xiàn)類重寫的。實現(xiàn)類自己的不能調用。
- 抽象類
35.抽象類使用規(guī)則
繼承抽象類的子類必須重寫父類所有的抽象方法。否則,該子類也必須聲明為抽象類。最終,必須有子類能夠實現(xiàn)完剩下的全部抽象方法,否則,從最初的父類到最終的子類都不能創(chuàng)建對象,失去意義。?如果A是抽象類,B繼承A,必須得繼承全部的。否則B也是個抽象類,不能創(chuàng)建對象。C去繼承B的話,得繼承完剩下的B沒繼承A的,如果方法B已經(jīng)繼承,可以重寫,但是要等到C重寫了所有沒實現(xiàn)的抽象類,才可以創(chuàng)建對象,去調用方法來使用。否則,C依然是個抽象類。
36.抽象類注意事項?
抽象類不能創(chuàng)建對象,如果創(chuàng)建,編譯無法通過而報錯。只能創(chuàng)建其非抽象子類的對象。抽象類中,可以有構造方法,是供子類創(chuàng)建對象時,初始化父類成員使用的。抽象類中,不一定包含抽象方法,但是有抽象方法的類必定是抽象類。
37.abstractclass和interface語法上有什么區(qū)別?
1.抽象類可以有構造方法,接口中不能有構造方法。2.抽象類中可以有普通成員變量,接口中沒有普通成員變量3.抽象類中可以包含非抽象的普通方法,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法。4. 抽象類中可以包含靜態(tài)方法,接口中不能包含靜態(tài)方法。5. 抽象類和接口中都可以包含靜態(tài)成員變量,抽象類中的靜態(tài)成員變量的訪問類型可以任意,但接口中定義的變量只能是publicstatic final類型,并且默認即為publicstatic final類型。6.一個類可以實現(xiàn)多個接口,但只能繼承一個抽象類。
38.接口是否可繼承接口?抽象類是否可繼承具體類(concreteclass)?抽象類中是否可以有靜態(tài)的main方法?
接口可以繼承接口。抽象類可以實現(xiàn)(implements)接口,抽象類可以繼承具體類。抽象類中可以有靜態(tài)的main方法。只要記?。撼橄箢惻c普通類的唯一區(qū)別就是不能創(chuàng)建實例對象和允許有abstract方法。
- 包裝類
39.什么是自動拆裝箱?
自動裝箱和拆箱,就是基本類型和引用類型之間的轉換。
40.為什么要轉換?
因為不能直接地向集合( Collection )中放入原始類型值,因為集合只接收對象。通常這種情況下你的做法是,將這些原始類型的值轉換成對象,然后將這些轉換的對象放入集合中。使用 Integer、Double、Boolean 等這些類,我們可以將原始類型值轉換成對應的對象,但是從某些程度可能使得代碼不是那么簡潔精煉。為了讓代碼簡練,Java5 引入了具有在原始類型和對象類型自動轉換的裝箱和拆箱機制。
- 泛型
41.你平時是如何使用泛型的?
1.使用含有泛型的類:在類上標注泛型代表我們還不知道是什么類型。等到測試類創(chuàng)建對象的時候確定泛型的類型。到時候類和方法的類型會變成相對應的類型。2.使用含有泛型的方法:在調用方法的時候確定泛型的類型。3.使用含有泛型的接口:第一種方式,創(chuàng)建泛型接口,接口上未確認泛型是什么類型。在實現(xiàn)類上決定泛型的類型。并且之后的所有實現(xiàn)方法都會默認是這個類型。第二種方式,接口已經(jīng)確認了泛型類型。實現(xiàn)類就得跟著用什么類型。如果一個子接口繼承了父接口,那么父接口如果確定了泛型類型,子接口也得跟著是什么類型。4.使用泛型通配符?:代表任意的數(shù)據(jù)類型使用方式:但它不能創(chuàng)建對象使用,只能作為方法的參數(shù)使用。
- 異常
42.Exeception和Error區(qū)別?
Exception 和 Error 都是繼承了 Throwable 類,在 Java 中只有 Throwable 類型的實例才可以被拋出(throw)或者捕獲(catch),它是異常處理機制的基本組成類型。?Exception 和 Error 體現(xiàn)了 Java 平臺設計者對不同異常情況的分類。Exception 是程序正常運行中,可以預料的意外情況,可能并且應該被捕獲,進行相應處理。?Error 是指在正常情況下,不大可能出現(xiàn)的情況,絕大部分的 Error 都會導致程序(比如 JVM 自身)處于非正常的、不可恢復狀態(tài)。既然是非正常情況,所以不便于也不需要捕獲,常見的比如 OutOfMemoryError 之類,都是 Error 的子類。?Exception 又分為可檢查(checked)異常和不可檢查(unchecked)異常:可檢查異常在源代碼里必須顯式地進行捕獲處理,這是編譯期檢查的一部分。前面我介紹的不可查的 Error,是 Throwable 不是 Exception。不檢查異常就是所謂的運行時異常,類似 NullPointerException、ArrayIndexOutOfBoundsException 之類,通常是可以編碼避免的邏輯錯誤,具體根據(jù)需要來判斷是否需要捕獲,并不會在編譯期強制要求。
43.那你知道異常有幾種處理方式嗎?
1.throws交給別人處理。步驟:只要我們在方法里面throw拋出一個異常,如果是RuntimeException或者其子類,就會默認給jvm接盤處理。jvm會中斷程序,打印到控制臺上。是jvm進行中斷處理的?否則,我們要在方法體throws上聲明,然后給下一個接盤者。?如果是在主方法調用,因為主方法調用了它,所以主方法要么處理異常,要么就繼續(xù)在主方法名上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(數(shù)組越界異常)NullPointerException(空指針異常)ArrayStoreException(數(shù)據(jù)存儲異常,操作數(shù)組時類型不一致)BufferOverflowException(還有IO操作的,緩沖溢出異常)
- 反射機制
46.什么是反射機制?
Class類對象階段是在內(nèi)存中的。已經(jīng)被編譯成字節(jié)碼加載進虛擬機內(nèi)存。這個時候對于我們用戶來說是看不到類的一些信息的,那我們?nèi)绻窒肟吹竭@些類的信息,就可以通過反射機制獲取,或者說當你無法確定到底傳入的類是什么樣子的時候,要通用兼容所有可能的類,就需要用反射機制動態(tài)去調用類的屬性和行為。
47.那怎么使用反射呢?
1.使用反射獲取字節(jié)碼Class對象:Class.forName("全類名")Class.forName("全類名")對象.getClass()?2.使用Class對象:通過Field類獲取成員變量通過Constructor類獲取構造方法通過Method類獲取成員方法
48.你反射這么熟悉,那一般在哪些場景用到它?。?/span>
1.逆向代碼 ,例如反編譯2.與注解相結合的框架3.動態(tài)獲取信息,動態(tài)代理(AOP中的動態(tài)代理:實現(xiàn)了接口的使用JDK的動態(tài)代理,沒有實現(xiàn)接口的使用CGlib動態(tài)代理)使用反射
49.聽你說的這么多,那它就沒有缺點嗎?
有的。它的性能是一個問題,反射相當于一系列解釋操作,通知jvm要做的事情,所以性能比直接的java代碼要慢很多。
- JDK1.8新特性
50.你知道JDK1.8有哪些新特性嗎?
1.函數(shù)式接口函數(shù)式接口指的是有且只有一個抽象方法的接口,并且接口中可以包含其它的方法。我們可以使用@FunctionalInterface注解去檢測一個接口是否是一個函數(shù)式接口常用的函數(shù)式接口有:Supplier接口:它是一個生產(chǎn)型接口,當你指定接口是什么類型時,接口的get方法就會生產(chǎn)什么類型的數(shù)據(jù)Function接口:這個接口用來根據(jù)一個類型的數(shù)據(jù)去獲取另一個類型的數(shù)據(jù),前者稱為前置條件,后者稱為后置條件。這個接口中最主要的抽象方法為:R apply(T t),去根據(jù)類型T的參數(shù)獲取類型R的結果。使用場景有很多,比如:將String類型轉化為Integer類型。2.Stream流:Stream流屬于管道流,只能波消費(使用)一次第一個Stream流調用完畢方法,數(shù)據(jù)就會流轉到下一個Stream上而這時第一個Stream流已經(jīng)使用完畢,就會關閉了所以第一個Stream流就不能再調用方法了。常用方法:forEach():用來遍歷流中的數(shù)據(jù),是一個終結方法。遍歷之后就不能再調用Stream流中的其它方法了。filter():它可以傳遞lambda表達式,對數(shù)據(jù)進行過濾。map()::該接口需要一個Function函數(shù)式接口參數(shù),可以將當前流中的T數(shù)據(jù)轉換為另一種R類型的流。skip():如果希望跳過前幾個元素,可以使用skip方法獲取一個截取之后的新流。concat():如果有兩個流希望合并成一個流,那么使用Stream接口的靜態(tài)方法concat就可以3.Lambda表達式:lambda表達式的標準格式由三部分組成:1.箭頭 2.參數(shù) 3.代碼格式: (參數(shù)列表) -> {核心代碼};格式說明:() :接口中抽象方法的參數(shù)列表,沒有參數(shù)的時候就空著,有參數(shù)的話就正常寫出參數(shù),多個參數(shù)用逗號分割-> :傳遞的意思,把參數(shù)傳遞給方法體{}{} :重寫接口的抽象方法的方法體?對于Lambda表達式來說,真正重要的是參數(shù),方法體和返回值。其他的,都可以省略。
將最重要的《25大專題Java面試專題》筆記拿出來,免費分享給大家需要獲取的小伙伴可以直接轉發(fā) 關注后私信(學習)即可獲取到!
JavaOOP面試題
Java集合/泛型面試題
Java異常面試題
Java中的IO與NIO面試題
因為篇幅原因,大部分的內(nèi)容就不給大家一一展示了,需要獲取的小伙伴可以直接轉發(fā) 關注后私信(學習)即可獲取到!
學習資料大禮包:
涵蓋面試準備、項目經(jīng)驗、簡歷編寫、源碼學習、算法準備、面試資源等內(nèi)容
因為篇幅原因,大部分的內(nèi)容就不給大家一一展示了,需要獲取的小伙伴可以直接轉發(fā) 關注后私信(學習)即可獲取到!