1. 程式人生 > 其它 >面試必問知識點

面試必問知識點

1.什麼是面向物件?(談談你對面向物件的理解?)

可以和麵向過程對比理解,比如洗衣機洗衣服.

面向過程會將任務拆解成多個步驟,一個步驟分為一個函式

1.開啟洗衣機
2.放衣服
3.放洗衣粉
4.清洗
5.烘乾

面向物件程式設計將任務拆解成物件:人和洗衣機

人:
1.開啟洗衣機
2.放衣服
3.放洗衣粉

洗衣機:
1.清洗衣服
2.烘乾

面向過程更注重事情的步驟以及順序,面向物件更注重事情的參與者(物件)以及每個物件它需要做什麼事情

優缺點:

  • 面向過程更注重事情的本身,效能更加高效
  • 面向物件將任務拆分成多個物件,這樣更加易於複用,擴充套件和維護

面向物件的三大特性:繼承,多型,封裝

1.封裝性:它是將類中的一些隱私資料隱藏在類的內部,並且讓其無法被外界訪問和修改

2.繼承性:子類可以通過繼承來接受父類所有的公有的成員變數和方法(public修飾符)、受到保護的成員變數和方法protect修飾符)、預設的成員變數和方法

3.多型性:程式在執行過程中,同一型別在不同那個條件下表現不同的結果

封裝性體現方式:用private修飾符修飾的成員變數和成員方法,外界無法通過建立該類物件的方法對其中的私有變數進行修改。私有化屬性之後,通過對外提供setter和getter方法來使外界訪問屬性,也可以通過對外開放介面,控制程式中屬性的訪問級別。

封裝的目的就是增強安全性,外界只有通過提供的外部接口才能訪問類的私有成員和屬性。
繼承


關於繼承,java中一個類只能直接繼承一個父類(可以實現多個介面),並且只能繼承訪問非私有(private)的屬性和方法。子類可以通過重寫,來改變父類中方法的具體內容,方法的命名必須和父類中的方法相同。

繼承的主要目的就是程式碼複用,當父類中已經有所需要的方法或屬性時,新建立的子類只要新添新的方法與屬性,而無需重新定義父類的方法或屬性。
多型
多型可以分成兩種形式:設計時多型和執行時多型

設計時多型:過載

執行是多型:重寫

多型的主要目的是增強程式碼的靈活性,可以在特定的情況下使用特定的方法。

java應該儘量減少繼承關係,來降低耦合度,使用多型時,父類在呼叫方法時,優先呼叫子類的方法,如果子類未重寫,則再呼叫父類的方法

2.JDK、JRE、JVM三者間的聯絡與區別

JDK

JDK(Java SE Development Kit),Java標準開發包,它提供了編譯、執行Java程式所需的各種工具和資源,包括Java編譯器、Java執行時環境,以及常用的Java類庫等。

JRE

JRE( Java Runtime Environment) 、Java執行環境,用於解釋執行Java的位元組碼檔案。普通使用者而只需要安裝 JRE(Java Runtime Environment)來執行 Java 程式。而程式開發者必須安裝JDK來編譯、除錯程式。

JVM

 JVM(Java Virtual Mechinal),Java虛擬機器,是JRE的一部分。它是整個java實現跨平臺的最核心的部分,負責解釋執行位元組碼檔案,是可執行java位元組碼檔案的虛擬計算機。所有平臺的上的JVM向編譯器提供相同的介面,而編譯器只需要面向虛擬機器,生成虛擬機器能識別的程式碼,然後由虛擬機器來解釋執行。

 當使用Java編譯器編譯Java程式時,生成的是與平臺無關的位元組碼,這些位元組碼只面向JVM。不同平臺的JVM都是不同的,但它們都提供了相同的介面。JVM是Java程式跨平臺的關鍵部分,只要為不同平臺實現了相應的虛擬機器,編譯後的Java位元組碼就可以在該平臺上執行。

區別與聯絡

  • JDK 用於開發,JRE 用於執行java程式 ;如果只是執行Java程式,可以只安裝JRE,無序安裝JDK。
  • JDk包含JRE,JDK 和 JRE 中都包含 JVM。
  • JVM 是 java 程式語言的核心並且具有平臺獨立性。

3.==和equals的區別

1)對於==,比較的是值是否相等

如果作用於基本資料型別的變數,則直接比較其儲存的 值是否相等,

如果作用於引用型別的變數,則比較的是所指向的物件的地址是否相等。
其實==比較的不管是基本資料型別,還是引用資料型別的變數,比較的都是值,只是引用型別變數存的值是物件的地址

2)對於equals方法,比較的是是否是同一個物件

首先,equals()方法不能作用於基本資料型別的變數,

另外,equals()方法存在於Object類中,而Object類是所有類的直接或間接父類,所以說所有類中的equals()方法都繼承自Object類,在沒有重寫equals()方法的類中,呼叫equals()方法其實和使用==的效果一樣,也是比較的是引用型別的變數所指向的物件的地址,不過,Java提供的類中,有些類都重寫了equals()方法,重寫後的equals()方法一般都是比較兩個物件的值,比如String類。

先看下Object類equals()方法原始碼:

再看String類equals()方法原始碼:

4.final的作用

  • 修飾類(表明該類不可被繼承,類中的所有成員方法都隱式的被指定為final方法,成員變數則可以定義為final,也可以不定義為final)
  • 修飾方法
    (鎖定這個方法,防止任何繼承類修改它的含義
    提高效率:在方法前面新增final進行修飾可以提高效率,其原理是基於內聯/內嵌(inline)機制,它會使你在呼叫final方法時,直接將方法的主體插入到呼叫處,從而省去呼叫函式所花費的開銷。但是如果方法過於龐大或者其中有迴圈的話,這種提高效率的方法可能會失效)
  • 修飾變數(final對變數的修飾的作用,是防止變數值的改變)

如果修飾的是基本型別資料變數,則該變數的值不能發生改變;
如果修飾的是引用型別資料變數,則該變數不會內二次初始化.
** 強調:**

  1. 由於引用型別資料變數被初始化後,其值是一個地址,所以不會被二次初始化,則地址不改變。
  2. 當用final作用於類的成員變數時,成員變數(注意是類的成員變數,區域性變數只需要保證在使用之前被初始化賦值即可)必須在定義時或者構造器中進行初始化賦值,而且final變數一旦被初始化賦值之後,就不能再被賦值了。
  3. 引用變數被final修飾之後,雖然不能再指向其他物件,但是它指向的物件的內容是可變的。
  4. static作用於成員變數用來表示只儲存一份副本,而final的作用是用來保證變數不可變。

5.String,StringBuffer,StringBuilder區別和使用場景

String


可以看到它是final修飾的,是不可變的字串,也就是說在做一些操作比如拼接字串,其實是產生一個新的物件,當業務對字串的內容操作頻繁,每一次都會建立一個新的字串物件,這樣就會造成一些記憶體浪費,建議使用StringBuffer,StringBuilder.

StringBuffer和StringBuilder

相同點:

可變字串,做字串拼接的時候,始終操作的是原物件,就不會去不斷產生一個新的物件

區別:

StringBuffer:執行緒安全,因為內部方法都加了synchronized關鍵字,不需要額外加鎖

StringBuilder:執行緒不安全,實現執行緒安全需要額外加鎖實現

三者使用場景總結

   1.如果要操作少量的資料用 String
   2.單執行緒操作字串緩衝區下操作大量資料 StringBuilder
   3.多執行緒操作字串緩衝區下操作大量資料 StringBuffer

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

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

過載發生在一個類中,同名的方法如果有不同的引數列表(引數型別不同、引數個數不同或者二者都不同)則視為過載;

  重寫發生在子類與父類之間,重寫要求子類被重寫方法與父類被重寫方法有相同的引數列表,相同的返回型別和相同的方法名,不能比父類被重寫方法宣告更多的異常(里氏代換原則)。

  過載對返回型別沒有特殊的要求,不能根據返回型別進行區分。
注意:
1.子類中不能重寫父類中的final方法
2.子類中必須重寫父類中的abstract方法

7.抽象類和介面的區別

抽象類

抽象方法必須用abstract關鍵字進行修飾。如果一個類含有抽象方法,則稱這個類為抽象類,抽象類必須在類前用abstract關鍵字修飾。因為抽象類中含有無具體實現的方法,所以不能用抽象類建立物件。

抽象類可以擁有成員變數和普通的成員方法。

抽象類和普通類的主要有三點區別:
1)抽象方法必須為public或者protected(因為如果為private,則不能被子類繼承,子類便無法實現該方法),預設情況下預設為public。
2)抽象類不能用來建立物件;
3)如果一個類繼承於一個抽象類,則子類必須實現父類的抽象方法。如果子類沒有實現父類的抽象方法,則必須將子類也定義為為abstract類。

介面

介面中的變數會被隱式地指定為public static final變數,並且只能是public static final變數,用private修飾會報編譯錯誤,而方法會被隱式地指定為public abstract方法且只能是public abstract方法,用其他關鍵字,比如private、protected、static、 final等修飾會報編譯錯誤,並且介面中所有的方法不能有具體的實現,也就是說,介面中的方法必須都是抽象方法。

抽象類和介面的區別:

語法層面上的區別
1)一個類只能繼承一個抽象類,而一個類卻可以實現多個介面;
2)抽象類中的成員變數可以是各種型別的,而介面中的成員變數只能是public static final型別的;
3)介面中不能含有靜態程式碼塊以及靜態方法,而抽象類可以有靜態程式碼塊和靜態方法;
4)抽象類可以提供成員方法的實現細節,而介面中只能存在public abstract 方法;
5)抽象類的抽象方法可以是public,protected,default型別,而介面的方法只能是public。
設計層面上的區別
1)抽象類的設計目的是達到程式碼的一種複用,是對類的本質的一個抽象,包括屬性、行為,表達的是"is a"關係,而介面的設計目的是約束類的一個行為,約束這一個"有"的行為,提供了一種機制去讓不同的類具有相同的行為,只能約束行為的"有無",對行為的具體實現是不做約束的,是對行為的一個抽象,表達的是 "like a"的關係。
繼承是一個 "是不是"的關係,而 介面 實現則是 "有沒有"的關係。
2)設計層面不同,抽象類作為很多子類的父類,它是一種模板式設計。而介面是一種行為規範,它是一種輻射式設計。

8.hashCode和equals

hashCode(雜湊碼),hashCode方法是去獲取這個雜湊碼

我們知道我們的物件都是儲存在堆裡面的,堆裡面其實維護了一個hash表,雜湊碼是為了確認物件在雜湊表中的一個索引位置,雜湊表是以key-value形式儲存的,通過key(雜湊碼)快速找到物件在堆裡面的一個具體位置.

比如說有個物件要加入到hashSet裡面去,hashSet首先通過hashCode()方法會去獲取它的一個雜湊值,通過雜湊值在雜湊表中找到具體位置,看是不是有值,如果沒有就加入,有的話在進行equals進行比較,如果結果為true(物件相等)就不加入,為fasle(物件不相等)就重新將這個物件雜湊到別的位置去.

如果沒有hashCode,我們需要將雜湊表的所有物件拿出來與新物件進行equals比較,由於equals對比的是記憶體,效能是很慢的,有了hashCode就不需要進行全部對比,就會大大提升執行的速度

兩個物件相等,那麼hashCode一定是相等的,兩個物件用equals比較返回的是true,hashCode不一定相等
equals方法被覆蓋的話,hashCode方法也必須被覆蓋