1. 程式人生 > >32道常見的Java基礎面試題

32道常見的Java基礎面試題

語言 ins 替換 param 用戶登錄 懶漢模式 工作 你在 protected

1. 什麽是 Java 虛擬機(JVM)?為什麽 Java 被稱作是“平臺無關的編程語言”?

Java 虛擬機是一個可以執行 Java 字節碼的虛擬機進程。Java 源文件被編譯成能被 Java 虛擬機執行的字節碼文件。

Java 被設計成允許應用程序可以運行在任意的平臺,而不需要程序員為每一個平臺單獨重寫或者是重新編譯。Java 虛擬機讓這個變為可能,因為它知道底層硬件平臺的指令長度和其他特性。

2. JDK、JRE、JVM 分別是什麽關系?

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

JRE 即為 Java 運行環境,提供了運行 Java 應用程序所必須的軟件環境,包含有 Java 虛擬機(JVM)和豐富的系統類庫。系統類庫即為 Java 提前封裝好的功能類,只需拿來直接使用即可,可以大大的提高開發效率。

JVM 即為 Java 虛擬機,提供了字節碼文件(.class)的運行環境支持。 簡單說,就是 JDK 包含 JRE 包含 JVM。

3. Java 支持的數據類型有哪些?

Java 支持的數據類型包括基本數據類型和引用類型。基本數據類型如下。

整數值型:byte,short,int,long

字符型:char

浮點類型:float,double

布爾型:boolean

整數默認 int 型,小數默認是 double 型。Float 和 long 類型的必須加後綴。比如 float f = 100f。

首先知道 String 是引用類型不是基本類型,引用類型聲明的變量是指該變量在內存中實際存儲的是一個引用地址,實體在堆中。引用類型包括類、接口、數組等。String 類還是 final 修飾的。

4. 什麽是自動拆裝箱?

自動裝箱和拆箱就是基本類型和引用類型之間的轉換,至於為什麽要轉換,因為基本類型轉換為引用類型後,就可以 new 對象,從而調用包裝類中封裝好的方法進行基本類型之間的轉換或者 toString(當然用類名直接調用也可以,便於一眼看出該方法是靜態的),還有就是如果集合中想存放基本類型,泛型的限定類型只能是對應的包裝類型。

5. 什麽是面向對象?

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

6. 面向對象的四大基本特性?

抽象:提取現實世界中某事物的關鍵特性,為該事物構建模型的過程。對同一事物在不同的需求下,需要提取的特性可能不一樣。得到的抽象模型中一般包含:屬性(數據)和操作(行為)。這個抽象模型我們稱之為類,對類進行實例化得到對象。

封裝:封裝可以使類具有獨立性和隔離性,保證類的高內聚。只暴露給類外部或者子類必須的屬性和操作。類封裝的實現依賴類的修飾符(public、protected 和 private 等)。

繼承:對現有類的一種復用機制。一個類如果繼承現有的類,則這個類將擁有被繼承類的所有非私有特性(屬性和操作)。這裏指的繼承包含:類的繼承和接口的實現。

多態:多態是在繼承的基礎上實現的。多態的三個要素:繼承、重寫和父類引用指向子類對象。父類引用指向不同的子類對象時,調用相同的方法,呈現出不同的行為,就是類多態特性。多態可以分成編譯時多態和運行時多態。

抽象、封裝、繼承和多態是面向對象的基礎。

7. & 與 && 的區別?

& 運算符有兩種用法:(1) 按位與,(2) 邏輯與。&& 運算符是短路與運算。

邏輯與跟短路與的差別是非常巨大的,雖然二者都要求運算符左右兩端的布爾值都是 true 整個表達式的值才是 true。&& 之所以稱為短路運算是因為,如果 && 左邊的表達式的值是 false,右邊的表達式會被直接短路掉,不會進行運算。

很多時候我們可能都需要用 && 而不是 &,例如在驗證用戶登錄時判定用戶名不是 null 而且不是空字符串,應當寫為:

1username != null && !username.equals(“”)

二者的順序不能交換,更不能用 & 運算符,因為第一個條件如果不成立,根本不能進行字符串的 equals 比較,否則會產生 NullPointerException 異常。

註意:邏輯或運算符(|)和短路或運算符(||)的差別也是如此。

8. 什麽是值傳遞和引用傳遞?

值傳遞是對基本型變量而言的,傳遞的是該變量的一個副本,改變副本不影響原變量。

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

9. 是否可以在 static 環境中訪問非 static 變量?

static 變量在 Java 中是屬於類的,它在所有的實例中的值是一樣的。當類被 Java 虛擬機載入的時候,會對 static 變量進行初始化。如果你的代碼嘗試不用實例來訪問非 static 的變量,編譯器會報錯,因為這些變量還沒有被創建出來,還沒有跟任何實例關聯上。

10. Java 中的方法覆蓋(Overriding)和方法重載(Overloading)是什麽意思?

Java 中的方法重載發生在同一個類裏面兩個或者是多個方法的方法名相同但是參數不同的情況。與此相對,方法覆蓋是說子類重新定義了父類的方法。方法覆蓋必須有相同的方法名,參數列表和返回類型。覆蓋者可能不會限制它所覆蓋的方法的訪問。

11. Java 支持多繼承麽?

Java 中類不支持多繼承,只支持單繼承(即一個類只有一個父類)。 但是 Java 中的接口支持多繼承,即一個子接口可以有多個父接口。(接口的作用是用來擴展對象的功能,一個子接口繼承多個父接口,說明子接口擴展了多個功能,當類實現接口時,類就擴展了相應的功能)。

12. Java 中,什麽是構造方法?什麽是構造方法重載?什麽是復制構造方法?

當新對象被創建的時候,構造方法會被調用。每一個類都有構造方法。在程序員沒有給類提供構造方法的情況下,Java 編譯器會為這個類創建一個默認的構造方法。

Java 中構造方法重載和方法重載很相似。可以為一個類創建多個構造方法。每一個構造方法必須有它自己唯一的參數列表。

Java 不支持像 C++ 中那樣的復制構造方法,這個不同點是因為如果你不自己寫構造方法的情況下,Java 不會創建默認的復制構造方法。

13. 接口和抽象類的區別是什麽?

從設計層面來說,抽象是對類的抽象,是一種模板設計,接口是行為的抽象,是一種行為的規範。

Java 提供和支持創建抽象類和接口。它們的實現有共同點,不同點在於: 接口中所有的方法隱含的都是抽象的,而抽象類則可以同時包含抽象和非抽象的方法。

類可以實現很多個接口,但是只能繼承一個抽象類。類可以不實現抽象類和接口聲明的所有方法,當然,在這種情況下,類也必須得聲明成是抽象的。

抽象類可以在不提供接口方法實現的情況下實現接口。 Java 接口中聲明的變量默認都是 final 的。抽象類可以包含非 final 的變量。Java 接口中的成員函數默認是 public 的。抽象類的成員函數可以是 private,protected 或者是 public。

接口是絕對抽象的,不可以被實例化。抽象類也不可以被實例化,但是,如果它包含 main 方法的話是可以被調用的。也可以參考 JDK8 中抽象類和接口的區別。

14. 用最有效率的方法計算 2 乘以 8?

2 << 3(左移3位相當於乘以2的3次方,右移3位相當於除以2的3次方)。

15. 手寫單例模式(餓漢和懶漢模式)和工廠模式?

餓漢模式

//餓漢式單例類.在類初始化時,已經自行實例化
public class Singleton1 {
//私有的默認構造子
private Singleton1() {}
//已經自行實例化
private static final Singleton1 single = new Singleton1();
//靜態工廠方法
public static Singleton1 getInstance() {
return single;
}
}

懶漢模式

//懶漢式單例類.在第一次調用的時候實例化
public class Singleton2 {
//私有的默認構造子
private Singleton2() {}
//註意,這裏沒有final
private static Singleton2 single=null;
//靜態工廠方法
public synchronized static Singleton2 getInstance() {
if (single == null) {
single = new Singleton2();
}
return single;
}
}

工廠模式,也可以參考之前的設計模式中的工廠模式,文末有鏈接。

interface IFactory{
public IProduct createProduct();
}

Class Factory implements IFactory{
public IProduct createProduct()
{
return new Product();
}
}

Public class client{
Public Static void main (String [] args){
IFactory factory=new Factory();
IProduct product=factory.createProduct();
product.ProductMethod();
}
}

16. String和StringBuilder、StringBuffer的區別?

Java 平臺提供了兩種類型的字符串:String 和 StringBuffer/StringBuilder,它們可以儲存和操作字符串。

其中 String 是只讀字符串,也就意味著 String 引用的字符串內容是不能被改變的。

而 StringBuffer/StringBuilder 類表示的字符串對象可以直接進行修改。StringBuilder 是 Java 5 中引入的,它和 StringBuffer 的方法完全相同,區別在於它是在單線程環境下使用的,因為它的所有方面都沒有被 synchronized 修飾,因此它的效率也比 StringBuffer 要高。

17. Java 集合框架有哪些?說出一些集合框架的優點?

每種編程語言中都有集合,最初的 Java 版本包含幾種集合類:Vector、Stack、HashTable 和 Array。隨著集合的廣泛使用,Java1.2 提出了囊括所有集合接口、實現和算法的集合框架。在保證線程安全的情況下使用泛型和並發集合類,Java 已經經歷了很久。它還包括在 Java 並發包中,阻塞接口以及它們的實現。集合框架的部分優點如下:
(1)使用核心集合類降低開發成本,而非實現我們自己的集合類。
(2)隨著使用經過嚴格測試的集合框架類,代碼質量會得到提高。
(3)通過使用 JDK 附帶的集合類,可以降低代碼維護成本。
(4)復用性和可操作性。

18. 集合框架中的泛型有什麽優點?

Java1.5 引入了泛型,所有的集合接口和實現都大量地使用它。泛型允許我們為集合提供一個可以容納的對象類型。因此,如果你添加其它類型的任何元素,它會在編譯時報錯。這避免了在運行時出現 ClassCastException,因為你將會在編譯時得到報錯信息。泛型也使得代碼整潔,我們不需要使用顯式轉換和 instanceOf 操作符。它也給運行時帶來好處,因為不會產生類型檢查的字節碼指令。

19. Java 集合框架的基礎接口有哪些?

Collection 為集合層級的根接口。一個集合代表一組對象,這些對象即為它的元素。Java 平臺不提供這個接口任何直接的實現。

Set 是一個不能包含重復元素的集合。這個接口對數學集合抽象進行建模,被用來代表集合,就如一副牌。

List 是一個有序集合,可以包含重復元素。你可以通過它的索引來訪問任何元素。List 更像長度動態變換的數組。

Map 是一個將 key 映射到 value 的對象。一個 Map 不能包含重復的 key,每個 key 最多只能映射一個 value。

一些其它的接口有 Queue、Dequeue、SortedSet、SortedMap 和 ListIterator。

20. 為何 Collection 不從 Cloneable 和 Serializable 接口繼承?

Collection 接口指定一組對象,對象即為它的元素。如何維護這些元素由 Collection 的具體實現決定。例如,一些如 List 的 Collection 實現允許重復的元素,而其它的如 Set 就不允許。很多 Collection 實現有一個公有的 clone 方法。然而,把它放到集合的所有實現中也是沒有意義的。這是因為 Collection 是一個抽象表現,重要的是實現。

當與具體實現打交道的時候,克隆或序列化的語義和含義才發揮作用。所以,具體實現應該決定如何對它進行克隆或序列化,或它是否可以被克隆或序列化。在所有的實現中授權克隆和序列化,最終導致更少的靈活性和更多的限制,特定的實現應該決定它是否可以被克隆和序列化。

21. 為何 Map 接口不繼承 Collection 接口?

盡管 Map 接口和它的實現也是集合框架的一部分,但 Map 不是集合,集合也不是 Map。因此,Map 繼承 Collection 毫無意義,反之亦然。

如果 Map 繼承 Collection 接口,那麽元素去哪兒?Map 包含key-value 對,它提供抽取 key 或 value 列表集合的方法,但是它不適合“一組對象”規範。

22. 什麽是叠代器(Iterator)?

Iterator 接口提供了很多對集合元素進行叠代的方法。每一個集合類都包含了可以返回叠代器實例的叠代方法。叠代器可以在叠代的過程中刪除底層集合的元素,但是不可以直接調用集合的 remove(Object Obj) 刪除,可以通過叠代器的 remove() 方法刪除。

23. Iterator 和 ListIterator 的區別是什麽?

Iterator 可用來遍歷 Set 和 List 集合,但是 ListIterator 只能用來遍歷 List。

Iterator 對集合只能是前向遍歷,ListIterator 既可以前向也可以後向。

ListIterator 實現了 Iterator 接口,並包含其他的功能。比如:增加元素,替換元素,獲取前一個和後一個元素的索引等等。

24. Java 中的 HashMap 的工作原理是什麽?

我們知道在 Java 中最常用的兩種結構是數組和模擬指針(引用),幾乎所有的數據結構都可以利用這兩種來組合實現,HashMap 也是如此。實際上 HashMap 是一個“鏈表散列”。

HashMap 是基於 hashing 的原理,我們使用 put(key, value) 存儲對象到 HashMap 中,使用 get(key) 從 HashMap 中獲取對象。當我們給 put() 方法傳遞鍵和值時,我們先對鍵調用 hashCode() 方法,返回的 hashCode 用於找到 bucket 位置來儲存 Entry 對象。

25. 當兩個對象的 hashcode 相同會發生什麽?

因為 hashcode 相同,所以它們的 bucket 位置相同,“碰撞”會發生。因為 HashMap 使用鏈表存儲對象,這個 Entry(包含有鍵值對的 Map.Entry 對象)會存儲在鏈表中。

26. 如果兩個鍵的 hashcode 相同,你如何獲取值對象?

當我們調用 get() 方法,HashMap 會使用鍵對象的 hashcode 找到 bucket 位置,然後會調用 keys.equals() 方法去找到鏈表中正確的節點,最終找到要找的值對象。

27. hashCode() 和 equals() 方法有何重要性?

HashMap 使用 Key 對象的 hashCode() 和 equals() 方法去決定 key-value 對的索引。當我們試著從 HashMap 中獲取值的時候,這些方法也會被用到。

如果這些方法沒有被正確地實現,在這種情況下,兩個不同 Key 也許會產生相同的 hashCode() 和 equals() 輸出,HashMap 將會認為它們是相同的,然後覆蓋它們,而非把它們存儲到不同的地方。

同樣的,所有不允許存儲重復數據的集合類都使用 hashCode() 和 equals() 去查找重復,所以正確實現它們非常重要。equals() 和 hashCode() 的實現應該遵循以下規則:

如果 o1.equals(o2),那麽o1.hashCode() == o2.hashCode()總是為true的。
如果 o1.hashCode() == o2.hashCode(),並不意味著o1.equals(o2)會為true。

28. HashMap 和 HashTable 有什麽區別?

1. HashMap 是非線程安全的,HashTable 是線程安全的。

2. HashMap 的鍵和值都允許有 null 值存在,而 HashTable 則不行。

3. 因為線程安全的問題,HashMap 效率比 HashTable 的要高。

4. HashTable 是同步的,而 HashMap 不是。因此,HashMap 更適合於單線程環境,而 HashTable 適合於多線程環境。

一般現在不建議用 HashTable,一是 HashTable 是遺留類,內部實現很多沒優化和冗余。二是即使在多線程環境下,現在也有同步的 ConcurrentHashMap 替代,沒有必要因為是多線程而用 HashTable。

29. 如何決定選用 HashMap 還是 TreeMap?

對於在 Map 中插入、刪除和定位元素這類操作,HashMap 是最好的選擇。然而,假如你需要對一個有序的 key 集合進行遍歷, TreeMap 是更好的選擇。基於你的 collection 的大小,也許向 HashMap 中添加元素會更快,將 map 換為 TreeMap 進行有序 key 的遍歷。

30. ArrayList 和 Vector 有何異同點?

ArrayList 和 Vector 在很多時候都很類似。

(1)兩者都是基於索引的,內部由一個數組支持。

(2)兩者維護插入的順序,我們可以根據插入順序來獲取元素。

(3)ArrayList 和 Vector 的叠代器實現都是 fail-fast 的。

(4)ArrayList 和 Vector 兩者允許 null 值,也可以使用索引值對元素進行隨機訪問。

以下是ArrayList和Vector的不同點。

(1)Vector 是同步的,而 ArrayList 不是。然而,如果你尋求在叠代的時候對列表進行改變,你應該使用 CopyOnWriteArrayList。

(2)ArrayList 比 Vector 快,它因為有同步,不會過載。

(3)ArrayList 更加通用,因為我們可以使用 Collections 工具類輕易地獲取同步列表和只讀列表。

31. Array 和 ArrayList 有何區別?什麽時候更適合用 Array?

Array 可以容納基本類型和對象,而 ArrayList 只能容納對象。 Array 是指定大小的,而 ArrayList 大小是固定的。Array 沒有提供 ArrayList 那麽多功能,比如 addAll、removeAll 和 iterator 等。盡管 ArrayList 明顯是更好的選擇,但也有些時候 Array 比較好用,比如下面的三種情況。
(1)如果列表的大小已經指定,大部分情況下是存儲和遍歷它們。
(2)對於遍歷基本數據類型,盡管 Collections 使用自動裝箱來減輕編碼任務,在指定大小的基本類型的列表上工作也會變得很慢。
(3)如果你要使用多維數組,使用 [][] 比 List。

32. 快速失敗(fail-fast)和安全失敗(fail-safe)的區別是什麽?

快速失敗:當你在叠代一個集合的時候,如果有另一個線程正在修改你正在訪問的那個集合時,就會拋出一個 ConcurrentModification 異常。 在 java.util 包下的都是快速失敗。

安全失敗:你在叠代的時候會去底層集合做一個拷貝,所以你在修改上層集合的時候是不會受影響的,不會拋出 ConcurrentModification 異常。在java.util.concurrent 包下的全是安全失敗的。

如果你有任何問題,都可以通過下面WX來懟我。

加的時候備註一下「博友」

技術分享圖片

32道常見的Java基礎面試題