1. 程式人生 > >史上最全Java面試題(帶全部答案,你可能要收藏!)

史上最全Java面試題(帶全部答案,你可能要收藏!)

原文地址:

前幾天,有朋友去面試之前問我關於後端架構相關的問題,但奈於我去年更多的工作是在移動SDK開發上,對此有所遺忘,實屬無奈,後面準備總結下.

今天要談的主題是關於求職.求職是在每個技術人員的生涯中都要經歷多次,對於我們大部分人而言,在進入自己心儀的公司之前少不了準備工作,有一份全面細緻面試題將幫助我們減少許多麻煩.在跳槽季來臨之前,特地做這個系列的文章,一方面幫助自己鞏固下基礎,另一方面也希望幫助想要換工作的朋友.

從12年開始,我先後做過爬蟲,搜尋,機器學習,javaEE及Android等方面的事情,而其中主要的工具便是Java和C,所以這個系列的重點也放在這兩方面.感興趣的朋友可以關注:

https://github.com/closedevice/interview-about.

為了更好的樹立知識體系,我附加了相關的思維導圖,分為pdf版和mindnote版.比如java相關的導圖如下:
這裡寫圖片描述

由於時間倉促,有些地方未寫完,後面會繼續補充.如有不妥之處,歡迎及時與我溝通.

相關概念

面向物件的三個特徵

封裝,繼承,多型.這個應該是人人皆知.有時候也會加上抽象.

多型的好處

允許不同類物件對同一訊息做出響應,即同一訊息可以根據傳送物件的不同而採用多種不同的行為方式(傳送訊息就是函式呼叫).主要有以下優點:

  1. 可替換性:多型對已存在程式碼具有可替換性.
  2. 可擴充性:增加新的子類不影響已經存在的類結構.
  3. 介面性:多型是超類通過方法簽名,向子類提供一個公共介面,由子類來完善或者重寫它來實現的.
  4. 靈活性:
  5. 簡化性:

程式碼中如何實現多型

實現多型主要有以下三種方式:
1. 介面實現
2. 繼承父類重寫方法
3. 同一類中進行方法過載

虛擬機器是如何實現多型的

動態繫結技術(dynamic binding),執行期間判斷所引用物件的實際型別,根據實際型別呼叫對應的方法.

介面的意義

介面的意義用三個詞就可以概括:規範,擴充套件,回撥.

抽象類的意義

抽象類的意義可以用三句話來概括:

  1. 為其他子類提供一個公共的型別
  2. 封裝子類中重複定義的內容
  3. 定義抽象方法,子類雖然有不同的實現,但是定義時一致的

介面和抽象類的區別

比較抽象類介面
預設方法抽象類可以有預設的方法實現,java 8之前,介面中不存在方法的實現.
實現方式子類使用extends關鍵字來繼承抽象類.如果子類不是抽象類,子類需要提供抽象類中所宣告方法的實現.子類使用implements來實現介面,需要提供介面中所有宣告的實現.
構造器抽象類中可以有構造器,介面中不能
和正常類區別抽象類不能被例項化介面則是完全不同的型別
訪問修飾符抽象方法可以有public,protected和default等修飾介面預設是public,不能使用其他修飾符
多繼承一個子類只能存在一個父類一個子類可以存在多個介面
新增新方法想抽象類中新增新方法,可以提供預設的實現,因此可以不修改子類現有的程式碼如果往介面中新增新方法,則子類中需要實現該方法.

父類的靜態方法能否被子類重寫

不能.重寫只適用於例項方法,不能用於靜態方法,而子類當中含有和父類相同簽名的靜態方法,我們一般稱之為隱藏.

什麼是不可變物件

不可變物件指物件一旦被建立,狀態就不能再改變。任何修改都會建立一個新的物件,如 String、Integer及其它包裝類。

靜態變數和例項變數的區別?

靜態變數儲存在方法區,屬於類所有.例項變數儲存在堆當中,其引用存在當前執行緒棧.

能否建立一個包含可變物件的不可變物件?

當然可以建立一個包含可變物件的不可變物件的,你只需要謹慎一點,不要共享可變物件的引用就可以了,如果需要變化時,就返回原物件的一個拷貝。最常見的例子就是物件中包含一個日期物件的引用.

java 建立物件的幾種方式

  1. 採用new
  2. 通過反射
  3. 採用clone
  4. 通過序列化機制

前2者都需要顯式地呼叫構造方法. 造成耦合性最高的恰好是第一種,因此你發現無論什麼框架,只要涉及到解耦必先減少new的使用.

switch中能否使用string做引數

在idk 1.7之前,switch只能支援byte,short,char,int或者其對應的封裝類以及Enum型別。從idk 1.7之後switch開始支援String.

switch能否作用在byte,long上?

可以用在byte上,但是不能用在long上.

String s1=”ab”,String s2=”a”+”b”,String s3=”a”,String s4=”b”,s5=s3+s4請問s5==s2返回什麼?

返回false.在編譯過程中,編譯器會將s2直接優化為”ab”,會將其放置在常量池當中,s5則是被建立在堆區,相當於s5=new String(“ab”);

你對String物件的intern()熟悉麼?

intern()方法會首先從常量池中查詢是否存在該常量值,如果常量池中不存在則現在常量池中建立,如果已經存在則直接返回.
比如
String s1=”aa”;
String s2=s1.intern();
System.out.print(s1==s2);//返回true

Object中有哪些公共方法?

  1. equals()
  2. clone()
  3. getClass()
  4. notify(),notifyAll(),wait()
  5. toString

java當中的四種引用

強引用,軟引用,弱引用,虛引用.不同的引用型別主要體現在GC上:

  1. 強引用:如果一個物件具有強引用,它就不會被垃圾回收器回收。即使當前記憶體空間不足,JVM也不會回收它,而是丟擲 OutOfMemoryError 錯誤,使程式異常終止。如果想中斷強引用和某個物件之間的關聯,可以顯式地將引用賦值為null,這樣一來的話,JVM在合適的時間就會回收該物件
  2. 軟引用:在使用軟引用時,如果記憶體的空間足夠,軟引用就能繼續被使用,而不會被垃圾回收器回收,只有在記憶體不足時,軟引用才會被垃圾回收器回收。
  3. 弱引用:具有弱引用的物件擁有的生命週期更短暫。因為當 JVM 進行垃圾回收,一旦發現弱引用物件,無論當前記憶體空間是否充足,都會將弱引用回收。不過由於垃圾回收器是一個優先順序較低的執行緒,所以並不一定能迅速發現弱引用物件
  4. 虛引用:顧名思義,就是形同虛設,如果一個物件僅持有虛引用,那麼它相當於沒有引用,在任何時候都可能被垃圾回收器回收。

WeakReference與SoftReference的區別?

這點在四種引用型別中已經做了解釋,這裡簡單說明一下即可:
雖然 WeakReference 與 SoftReference 都有利於提高 GC 和 記憶體的效率,但是 WeakReference ,一旦失去最後一個強引用,就會被 GC 回收,而軟引用雖然不能阻止被回收,但是可以延遲到 JVM 記憶體不足的時候。

為什麼要有不同的引用型別

不像C語言,我們可以控制記憶體的申請和釋放,在Java中有時候我們需要適當的控制物件被回收的時機,因此就誕生了不同的引用型別,可以說不同的引用型別實則是對GC回收時機不可控的妥協.有以下幾個使用場景可以充分的說明:

  1. 利用軟引用和弱引用解決OOM問題:用一個HashMap來儲存圖片的路徑和相應圖片物件關聯的軟引用之間的對映關係,在記憶體不足時,JVM會自動回收這些快取圖片物件所佔用的空間,從而有效地避免了OOM的問題.
  2. 通過軟引用實現Java物件的快取記憶體:比如我們建立了一Person的類,如果每次需要查詢一個人的資訊,哪怕是幾秒中之前剛剛查詢過的,都要重新構建一個例項,這將引起大量Person物件的消耗,並且由於這些物件的生命週期相對較短,會引起多次GC影響效能。此時,通過軟引用和 HashMap 的結合可以構建快取記憶體,提供效能.

java中==和eqauls()的區別,equals()和`hashcode的區別

==是運算子,用於比較兩個變數是否相等,而equals是Object類的方法,用於比較兩個物件是否相等.預設Object類的equals方法是比較兩個物件的地址,此時和==的結果一樣.換句話說:基本型別比較用==,比較的是他們的值.預設下,物件用==比較時,比較的是記憶體地址,如果需要比較物件內容,需要重寫equal方法

equals()hashcode()的聯絡

hashCode()是Object類的一個方法,返回一個雜湊值.如果兩個物件根據equal()方法比較相等,那麼呼叫這兩個物件中任意一個物件的hashCode()方法必須產生相同的雜湊值.
如果兩個物件根據eqaul()方法比較不相等,那麼產生的雜湊值不一定相等(碰撞的情況下還是會相等的.)

a.hashCode()有什麼用?與a.equals(b)有什麼關係

hashCode() 方法是相應物件整型的 hash 值。它常用於基於 hash 的集合類,如 Hashtable、HashMap、LinkedHashMap等等。它與 equals() 方法關係特別緊密。根據 Java 規範,使用 equal() 方法來判斷兩個相等的物件,必須具有相同的 hashcode。

將物件放入到集合中時,首先判斷要放入物件的hashcode是否已經在集合中存在,不存在則直接放入集合.如果hashcode相等,然後通過equal()方法判斷要放入物件與集合中的任意物件是否相等:如果equal()判斷不相等,直接將該元素放入集合中,否則不放入.

有沒有可能兩個不相等的物件有相同的hashcode

有可能,兩個不相等的物件可能會有相同的 hashcode 值,這就是為什麼在 hashmap 中會有衝突。如果兩個物件相等,必須有相同的hashcode 值,反之不成立.

可以在hashcode中使用隨機數字嗎?

不行,因為同一物件的 hashcode 值必須是相同的

a==b與a.equals(b)有什麼區別

如果a 和b 都是物件,則 a==b 是比較兩個物件的引用,只有當 a 和 b 指向的是堆中的同一個物件才會返回 true,而 a.equals(b) 是進行邏輯比較,所以通常需要重寫該方法來提供邏輯一致性的比較。例如,String 類重寫 equals() 方法,所以可以用於兩個不同物件,但是包含的字母相同的比較。

3*0.1==0.3返回值是什麼

false,因為有些浮點數不能完全精確的表示出來。

a=a+b與a+=b有什麼區別嗎?

+=操作符會進行隱式自動型別轉換,此處a+=b隱式的將加操作的結果型別強制轉換為持有結果的型別,而a=a+b則不會自動進行型別轉換.如:
byte a = 127;
byte b = 127;
b = a + b; // error : cannot convert from int to byte
b += a; // ok
(譯者注:這個地方應該表述的有誤,其實無論 a+b 的值為多少,編譯器都會報錯,因為 a+b 操作會將 a、b 提升為 int 型別,所以將 int 型別賦值給 byte 就會編譯出錯)

short s1= 1; s1 = s1 + 1; 該段程式碼是否有錯,有的話怎麼改?

有錯誤,short型別在進行運算時會自動提升為int型別,也就是說s1+1的運算結果是int型別.

short s1= 1; s1 += 1; 該段程式碼是否有錯,有的話怎麼改?

+=操作符會自動對右邊的表示式結果強轉匹配左邊的資料型別,所以沒錯.

& 和 &&的區別

首先記住&是位操作,而&&是邏輯運算子.另外需要記住邏輯運算子具有短路特性,而&不具備短路特性.

public class Test{
    static String name;

    public static void main(String[] args){
        if(name!=null&userName.equals("")){
            System.out.println("ok");
        }else{
            System.out.println("erro");
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

以上程式碼將會丟擲空指標異常.

一個.java檔案內部可以有類?(非內部類)

只能有一個public公共類,但是可以有多個default修飾的類.

如何正確的退出多層巢狀迴圈.

  1. 使用標號和break;
  2. 通過在外層迴圈中新增識別符號

內部類的作用

內部類可以有多個例項,每個例項都有自己的狀態資訊,並且與其他外圍物件的資訊相互獨立.在單個外圍類當中,可以讓多個內部類以不同的方式實現同一介面,或者繼承同一個類.建立內部類物件的時刻不依賴於外部類物件的建立.內部類並沒有令人疑惑的”is-a”關係,它就像是一個獨立的實體.

內部類提供了更好的封裝,除了該外圍類,其他類都不能訪問

final,finalize和finally的不同之處

final 是一個修飾符,可以修飾變數、方法和類。如果 final 修飾變數,意味著該變數的值在初始化後不能被改變。finalize 方法是在物件被回收之前呼叫的方法,給物件自己最後一個復活的機會,但是什麼時候呼叫 finalize 沒有保證。finally 是一個關鍵字,與 try 和 catch 一起用於異常的處理。finally 塊一定會被執行,無論在 try 塊中是否有發生異常。

clone()是哪個類的方法?

java.lang.Cloneable 是一個標示性介面,不包含任何方法,clone 方法在 object 類中定義。並且需要知道 clone() 方法是一個本地方法,這意味著它是由 c 或 c++ 或 其他本地語言實現的。

深拷貝和淺拷貝的區別是什麼?

淺拷貝:被複制物件的所有變數都含有與原來的物件相同的值,而所有的對其他物件的引用仍然指向原來的物件。換言之,淺拷貝僅僅複製所考慮的物件,而不復制它所引用的物件。

深拷貝:被複制物件的所有變數都含有與原來的物件相同的值,而那些引用其他物件的變數將指向被複制過的新物件,而不再是原有的那些被引用的物件。換言之,深拷貝把要複製的物件所引用的物件都複製了一遍。

static都有哪些用法?

幾乎所有的人都知道static關鍵字這兩