1. 程式人生 > 其它 >Java面試高頻題

Java面試高頻題

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

  繼承:讓某個型別的物件獲得另一個型別的物件的屬性的方法。繼承就是子類繼承父類的特徵和行為,使得子類物件(例項)具有父類的例項域和方法,或子類從父類繼承方法,使得子類具有父類相同的行        為。

  封裝:隱藏部分物件的屬性和實現細節,對資料的訪問只能通過外公開的介面。通過這種方式,物件對內部資料提供了不同級別的保護,以防止程式中無關的部分意外的改變或錯誤的使用了物件的私有部        分。

  多型:對於同一個行為,不同的子類物件具有不同的表現形式。

多型存在的3個條件:

  a.繼承;

  b.重寫;

  c.父類引用指向子類物件。

String和StringBuilder、StringBuffer的區別

  String:String 的值被建立後不能修改,任何對 String 的修改都會引發新的 String 物件的生成。

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

  StringBuilder:StringBuffer 的非執行緒安全版本,沒有使用 synchronized,具有更高的效能,推薦優先使用。

== 和 equals 的區別

  ==:運算子,用於比較基礎型別變數和引用型別變數。對於基礎型別變數,比較的變數儲存的值是否相同,型別不一定要相同。對於引用型別變數,比較的是兩個物件的地址是否相同。

  equals:Object 類中定義的方法,通常用於比較兩個物件的值是否相等。equals 在 Object 方法中其實等同於 ==,但是在實際的使用中,equals 通常被重寫用於比較兩個物件的值是否相同。

構造器是否可被重寫

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

過載(Overload)和重寫(Override)的區別

方法的過載和重寫都是實現多型的方式,區別在於前者實現的是編譯時的多型性,而後者實現的是執行時的多型性。

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

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

Error 和 Exception 有什麼區別

ErrorException 都是 Throwable 的子類,用於表示程式出現了不正常的情況。區別在於:

Error 表示系統級的錯誤和程式不必處理的異常,是恢復不是不可能但很困難的情況下的一種嚴重問題,比如記憶體溢位,不可能指望程式能處理這樣的情況。

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

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

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

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

修飾變數:該變數必須在宣告時給定初值,而在以後只能讀取,不可修改。 如果變數是物件,則指的是引用不可修改,但是物件的屬性還是可以修改的。版權協議,轉載請附上原文出處連結及本宣告。

闡述 final、finally、finalize 的區別

  final:該類不能再派生出新的子類,不能作為父類被繼承。因此,一個類不能同時被宣告為abstract 和 final。該方法不能被子類重寫。該變數必須在宣告時給定初值,而在以後只能讀取,不可修改。 如果變數是物件,則指的是引用不可修改,但是物件的屬性還是可以修改的。版權協議,轉載請附上原文出處連結及本宣告。

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

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

JDK1.8之後有哪些新特性

  介面預設方法:Java 8允許我們給介面新增一個非抽象的方法實現,只需要使用 default關鍵字即可

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

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

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

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

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

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

wait() 和 sleep() 方法的區別

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

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

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

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

List、Set、Map三者的區別

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

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

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

ArrayList 和 LinkedList 的區別。

  ArrayList 底層基於動態陣列實現,LinkedList 底層基於連結串列實現。

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

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

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

ArrayList 和 Vector 的區別

  Vector ArrayList 幾乎一致,唯一的區別是 Vector 在方法上使用了 synchronized 來保證執行緒安全,因此在效能上 ArrayList 具有更好的表現。

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

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

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

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 類。

Java 記憶體結構(執行時資料區)

  程式計數器:執行緒私有。一塊較小的記憶體空間,可以看作當前執行緒所執行的位元組碼的行號指示器。如果執行緒正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令的地址;如果正在執行的是Native方法,這個計數器值則為空。

  Java虛擬機器棧:執行緒私有。它的生命週期與執行緒相同。虛擬機器棧描述的是Java方法執行的記憶體模型:每個方法在執行的同時都會建立一個棧幀用於儲存區域性變量表、運算元棧、動態連結、方法出口等資訊。每一個方法從呼叫直至執行完成的過程,就對應著一個棧幀在虛擬機器棧中入棧到出棧的過程。

  本地方法棧:執行緒私有。本地方法棧與虛擬機器棧所發揮的作用是非常相似的,它們之間的區別不過是虛擬機器棧為虛擬機器執行Java方法(也就是位元組碼)服務,而本地方法棧則為虛擬機器使用到的Native方法服務。

  Java堆:執行緒共享。對大多數應用來說,Java堆是Java虛擬機器所管理的記憶體中最大的一塊。Java堆是被所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。此記憶體區域的唯一目的就是存放物件例項,幾乎所有的物件例項都在這裡分配記憶體。

  方法區:與Java堆一樣,是各個執行緒共享的記憶體區域,它用於儲存已被虛擬機器載入的類資訊(構造方法、介面定義)、常量、靜態變數、即時編譯器編譯後的程式碼(位元組碼)等資料。方法區是JVM規範中定義的一個概念,具體放在哪裡,不同的實現可以放在不同的地方。

  執行時常量池:執行時常量池是方法區的一部分。Class檔案中除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊是常量池,用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類載入後進入方法區的執行時常量池中存放。

Java虛擬機器中有哪些類載入器

  啟動類載入器(Bootstrap ClassLoader):這個類載入器負責將存放在<JAVA_HOME>\lib目錄中的,或者被-Xbootclasspath引數所指定的路徑中的,並且是虛擬機器識別的(僅按照檔名識別,如rt.jar,名字不符合的類庫即使放在lib目錄中也不會被載入)類庫載入到虛擬機器記憶體中。

  擴充套件類載入器(Extension ClassLoader):這個載入器由sun.misc.Launcher$ExtClassLoader實現,它負責載入<JAVA_HOME>\lib\ext目錄中的,或者被java.ext.dirs系統變數所指定的路徑中的所有類庫,開發者可以直接使用擴充套件類載入器。

  應用程式類載入器(Application ClassLoader):這個類載入器由sun.misc.Launcher$AppClassLoader實現。由於這個類載入器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也稱它為系統類載入器。它負責載入使用者類路徑(ClassPath)上所指定的類庫,開發者可以直接使用這個類載入器,如果應用程式中沒有自定義過自己的類載入器,一般情況下這個就是程式中預設的類載入器。

  自定義類載入器:使用者自定義的類載入器。

類載入的過程

類載入的過程包括:載入、驗證、準備、解析、初始化,其中驗證、準備、解析統稱為連線。

  載入:通過一個類的全限定名來獲取定義此類的二進位制位元組流,在記憶體中生成一個代表這個類的java.lang.Class物件。

  驗證:確保Class檔案的位元組流中包含的資訊符合當前虛擬機器的要求,並且不會危害虛擬機器自身的安全。

  準備:為靜態變數分配記憶體並設定靜態變數初始值,這裡所說的初始值“通常情況”下是資料型別的零值。

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

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