1. 程式人生 > 其它 >Java基礎常見面試題彙總

Java基礎常見面試題彙總

過載和重寫區別

過載:發生在一個類中,方法名相同,引數列表中的引數順序,型別,個數不同,方法的返回值和修飾符可以一樣也可以不一樣,存在於編譯期間

重寫:發生在子類中,子類允許對父類中允許訪問的方法進行重新編寫。

  1. 返回值型別、方法名、引數列表必須相同,丟擲的異常範圍小於等於父類,訪問修飾符範圍大於等於父類。
  2. 如果父類方法訪問修飾符為private/final/static則子類就不能重寫該方法,但是被 static 修飾的方法能夠被再次宣告。
  3. 構造方法無法被重寫

構造器能否被重寫

不能,重寫是子類方法重寫父類的方法,重寫的方法名不變,而類的構造方法名必須與類名一致,假設父類的構造方法如果能夠被子類重寫則子類類名必須與父類類名一致才行,所以Java 的構造方法是不能被重寫

談談Java三大特徵

封裝

封裝把一個物件的屬性私有化,同時提供一些可以被外界訪問的屬性的方法,如果屬性不想被外界訪問,我們大可不必提供方法給外界訪問。但是如果一個類沒有提供給外界訪問的方法,那麼這個類也沒有什麼意義了。

繼承

繼承是使用已存在的類的定義作為基礎建立新類的技術,新類的定義可以增加新的資料或新的功能,也可以用父類的功能,但不能選擇性地繼承父類。通過使用繼承我們能夠非常方便地複用以前的程式碼

多型

所謂多型就是指程式中定義的引用變數所指向的具體型別和通過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式執行期間才確定,即一個引用變數到底會指向哪個類的例項物件,該引用變數發出的方法呼叫到底是哪個類中實現的方法,必須在由程式執行期間才能決定。

在 Java 中有兩種形式可以實現多型:繼承(多個子類對同一方法的重寫)和介面(實現介面並覆蓋介面中同一方法)。

String str="abcd"String str1=new String("abcd")一樣嗎?str 和 str1 相等嗎?

這兩種不同的建立方法是有差別的。

  • 第一種方式先檢查字串常量池中有沒有"abcd",如果字串常量池中沒有,則建立一個,然後 str 指向字串常量池中的物件,如果有,則直接將 str 指向字串常量池中的"abcd"";

  • 第二種方式是直接在堆記憶體空間建立一個新的物件。

String,StringBuffer,StringBuilder區別?

String中使用了final 宣告 char[] values所以不可變,StringBuffer和StringBuilder繼承自AbstractStrignBuiler類,沒有使用final進行宣告,所以可以改變

String由於final修飾,不能更改,不能被繼承,所以執行緒安全

StringBuffer使用synchornized修飾,執行緒安全,StringBuffer執行緒不安全

StringBuffer由於synchornized修飾,所以效率低下

int和Integer區別

int是原始資料型別,Integer是他的包裝類

Integer預設值是null,int預設值是0

兩個通過new生成的Integer不會相等,因為new生成的是兩個物件

Integer和new Interger不會相等

Integer變數和int變數進行比較,只要兩個值相等,結果就為true(因為Integer會自動拆箱)

非new生成的Integer變數和new Integer()生成的變數比較時,結果為false

對於兩個非new生成的Integer物件,進行比較時,如果兩個變數的值在區間-128到127之間,則比較結果為true,如果兩個變數的值不在此區間,則比較結果為false

介面類和抽象類的區別

相同點:

1.兩者都能包含抽象方法

2.都是抽象類,不能被例項化

不同點:
介面類需要通過implements關鍵字進行實現,抽象類需要通過extend進行繼承

一個類可以實現多個介面,但是隻能繼承一個抽象類

介面類中的每一個方法都是抽象方法,都需要被實現類實現,抽象類中可以有選擇的實現

介面類的預設修飾符是public,而抽象類中的方法有public、protected 和 default 這些修飾符(抽象方法就是為了被重寫所以不能使用 private 關鍵字修飾!

所有方法在介面中不能有實現(Java 8 開始介面方法可以有預設實現),而抽象類可以有非抽象的方法

==和equals區別

==判斷的是兩個物件的地址值是否相同,即判斷兩個物件是不是同一個物件,基本資料型別==比較的是值,引用資料型別==比較的是記憶體地址

equals方法也是判斷兩個物件,如果equals在當前類沒有被重寫,那麼也是通過==判斷地址,如果重寫過了,就按照重寫的方法進行對比

hashcode和equals區別

hashCode() 的作用是獲取雜湊碼,也稱為雜湊碼;它實際上是返回一個 int 整數。這個雜湊碼的作用是確定該物件在雜湊表中的索引位置。hashCode() 定義在 JDK 的 Object.java 中,這就意味著 Java 中的任何類都包含有 hashCode() 函式。

hashCode()與 equals()的相關規定

  1. 如果兩個物件相等,則 hashcode 一定也是相同的;
  2. 兩個物件相等,對兩個物件分別呼叫 equals 方法都返回 true;
  3. 兩個物件有相同的 hashcode 值,它們也不一定是相等的(不同的物件也可能產生相同的 hashcode,概率性問題);
  4. 因此,equals 方法被覆蓋過,則 hashCode 方法也必須被覆蓋
  5. hashCode() 的預設行為是對堆上的物件產生獨特值。如果沒有重寫 hashCode(),則該 class 的兩個物件無論如何都不會相等(即使這兩個物件指向相同的資料)

什麼是反射機制,反射機制的應用場景

JAVA 反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為 java 語言的反射機制

  • 優點:執行期型別的判斷,動態載入類,提高程式碼靈活度。
  • 缺點:效能瓶頸:反射相當於一系列解釋操作,通知 JVM 要做的事情,效能比直接的 java 程式碼要慢很多

應用場景:

在很多的框架中都用了反射機制,比如Spring框架中對於配置檔案中bean的獲取,bean物件的動態代理物件等等

通過反射獲取物件類的方式?

  • 通過物件.getClass()方式

  • 通過類名.Class 方式

  • 通過Class.forName 方式

Java中IO流分為幾種

  • 按照流的流向分,可以分為輸入流和輸出流;
  • 按照操作單元劃分,可以劃分為位元組流和字元流;
  • 按照流的角色劃分為節點流和處理流。

IO/NIO/AIO區別

BIO:同步阻塞 I/O 模式,資料的讀取寫入必須阻塞在一個執行緒內等待其完成。在活動連線數不是特別高(小於單機 1000)的情況下,這種模型是比較不錯的,可以讓每一個連線專注於自己的 I/O 並且程式設計模型簡單,也不用過多考慮系統的過載、限流等問題

NIO:NIO 是一種同步非阻塞的 I/O 模型,在 Java 1.4 中引入了 NIO 框架,對應 java.nio 包,提供了 Channel , Selector,Buffer 等抽象。NIO 中的 N 可以理解為 Non-blocking,不單純是 New。它支援面向緩衝的,基於通道的 I/O 操作方法

AIO:AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改進版 NIO 2,它是非同步非阻塞的 IO 模型。非同步 IO 是基於事件和回撥機制實現的,也就是應用操作之後會直接返回,不會堵塞在那裡,當後臺處理完成,作業系統會通知相應的執行緒進行後續的操作

Java中建立物件的方式

  ①、通過 new 關鍵字

  這是最常用的一種方式,通過 new 關鍵字呼叫類的有參或無參構造方法來建立物件。比如 Object obj = new Object();

  ②、通過 Class 類的 newInstance() 方法

  這種預設是呼叫類的無參構造方法建立物件。比如 Person p2 = (Person) Class.forName("com.ys.test.Person").newInstance();

  ③、通過 Constructor 類的 newInstance 方法

  這和第二種方法類時,都是通過反射來實現。通過 java.lang.relect.Constructor 類的 newInstance() 方法指定某個構造器來建立物件。

  Person p3 = (Person) Person.class.getConstructors()[0].newInstance();

  實際上第二種方法利用 Class 的 newInstance() 方法建立物件,其內部呼叫還是 Constructor 的 newInstance() 方法。

  ④、利用 Clone 方法

  Clone 是 Object 類中的一個方法,通過 物件A.clone() 方法會建立一個內容和物件 A 一模一樣的物件 B,clone 克隆,顧名思義就是建立一個一模一樣的物件出來。

  Person p4 = (Person) p3.clone();

  ⑤、反序列化

  序列化是把堆記憶體中的 Java 物件資料,通過某種方式把物件儲存到磁碟檔案中或者傳遞給其他網路節點(在網路上傳輸)。而反序列化則是把磁碟檔案中的物件資料或者把網路節點上的物件資料,恢復成Java物件模型的過程。

淺拷貝與深拷貝

淺拷貝(clone):建立一個新物件,然後將當前物件的非靜態欄位複製到該新物件,如果欄位是值型別的,那麼對該欄位執行復制;如果該欄位是引用型別的話,則複製引用但不復制引用的物件。因此,原始物件及其副本引用同一個物件。

深拷貝:建立一個新物件,然後將當前物件的非靜態欄位複製到該新物件,無論該欄位是值型別的還是引用型別,都複製獨立的一份。當你修改其中一個物件的任何內容時,都不會影響另一個物件的內容。

Java中的單例設計模式

餓漢式:

public class Singleton {
    private static Singleton instance = new Singleton();
 
    // 私有化構造方法
    private Singleton() {
 
    }
 
    public static Singleton getInstance() {
        return instance;
    }
 
}

懶漢式:

public class Singleton {
    //2.本類內部建立物件例項
    private static Singleton instance = null;
 
    /**
         * 1.構造方法私有化,外部不能new
         */
    private Singleton() {
 
    }
 
//3.提供一個公有的靜態方法,返回例項物件
 
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
 

雙重檢驗執行緒安全的懶漢式:

public class Singleton {
    private volatile static Singleton instance = null;
 
    // 私有化構造方法
    private Singleton() {
 
    }
 
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
 
        }
        return instance;
    }
 
}