面試必問知識點
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對變數的修飾的作用,是防止變數值的改變)
如果修飾的是基本型別資料變數,則該變數的值不能發生改變;
如果修飾的是引用型別資料變數,則該變數不會內二次初始化.
** 強調:**
- 由於引用型別資料變數被初始化後,其值是一個地址,所以不會被二次初始化,則地址不改變。
- 當用final作用於類的成員變數時,成員變數(注意是類的成員變數,區域性變數只需要保證在使用之前被初始化賦值即可)必須在定義時或者構造器中進行初始化賦值,而且final變數一旦被初始化賦值之後,就不能再被賦值了。
- 引用變數被final修飾之後,雖然不能再指向其他物件,但是它指向的物件的內容是可變的。
- 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方法也必須被覆蓋