【JAVA面試題整理】JAVA基礎(一)

面向對象

一、面向對象都有哪些特性以及對這些特性的理解

1、繼承

繼承就是從已有的類中得到已有信息創建新類的過程,這個過程中,已有的類就是父類(超類、基類),新創建的類就是子類(派生類);繼承讓新的類有了一定的延續性

2、封裝

封裝通常意義理解爲把數據和操作數據的方法分開實現,將所有的數據項進行封裝,最終表現爲對數據進行隱藏,對方法進行暴露,只向外部提供最簡單的實現接口

3、多態

多態指不同的子類對象對同意操作做出不同的響應,比如A系統訪問B系統時,B系統提供多種服務方式,但是一切對於A來說都是透明的;

多態分爲運行時多態和編譯時多態,方法重載(overload)是編譯時多態(也稱前綁定),方法重寫(override)是運行時多態(也稱後綁定);

運行時多態是面向對象實現多態最精髓的東西,要做一下兩件事:

  1. 重寫父類方法;

  2.  對象造型(用父類引用子類對象,這樣會根據子類實現進而完成不同的實現方法,如Animal a= new Dog();Animal b = new Cat(););

4、抽象

抽象指對對象的屬性和行爲進行抽象化,在高度概括的基礎上,歸納出它的數據屬性和抽象行爲,而不關注具體實現。如接口和抽象類,本質上都只是整理出類的骨架,具體的實現方法放在子類中進行實現

二、訪問權限修飾符public、private、protected以及不寫(默認)的區別

修飾符

當前類

同包

子類

其他包

public

protected

×

default

×

×

private

×

×

×

三、爲什麼要clone?

當一個對象A已經賦了一些值,這時再重新new一個對象,再賦上同樣的值成本太高,所以纔要clone

四、new一個對象和clone一個對象的區別?

new一個對象要先查看new對象後面的對象類型,根據對象類型進行內存的分配,然後再調用構造函數,填充各個域,這一步叫對象的初始化,之後再把對象的引用(地址)發佈到外部,在外部就可以訪問、操作這個對象。

clone一個對象第一步和new對象一樣,都是根據對象的類型分配內存,然後根據原對象對clone出來的對象的各個域進行填充,最後再把對象的引用發佈到外部。

五、複製對象和clone的區別

看一下打印的結果:

對象的地址是一樣的,說明這兩個對象是一樣的。

這種方式叫做對象的複製,p和p1都只是對象的引用而已,對象只有一個。

下面的代碼實現了真正的clone:

看一下他的引用

從打印結果上看,兩者的引用地址是不一樣的,說明這是兩個不同的對象。

這是clone時,p和p1在內存中的場景,兩者指向的是不同的對象,只是對象的類型和值相同。

六、深拷貝和淺拷貝

上述代碼實例中,對Person對象已經進行了拷貝。由於age是基本類型int型,這個直接把具體的值拷貝過來沒有什麼爭議,但是name這個String類型的字段,這個String對象本身就是引用,指向一個真正的String對象,那麼拷貝它有兩種方式:

  1. 直接將原對象中引用值拷貝給新對象的name字段

  2. 根據原Person對象中的name指向,創建一個新的相同的String對象,將這個新的String對象的引用賦給新拷貝的Person對象的name字段

第一種方式叫淺拷貝,第二種叫深拷貝。

下面通過代碼對clone方法屬於淺拷貝還是深拷貝進行驗證

打印結果爲

所以p.clone()的方法是淺拷貝的。

那麼如何進行深拷貝?這就需要實現Cloneable接口,並且在clone()方法內部,把對應要深拷貝的對象也clone一份:

打印結果爲:

body和body1不是同一個對象,兩個head也不指向同一個地址,說明這種clone的方式是深拷貝。

JAVA語法

一、Java有沒有goto語句?

goto是java語言中的保留字,但是並沒有被使用。

二、&和&&的區別

&有兩種運算方式:

  1. 按位與;

  2. 邏輯與;

&&是短路與運算,當&&前的表達式爲false的時候,&&後的標的是就不再參與運算了。||運算符也同理。

三、如何跳出當前多重嵌套循環?

使用break和continue;

continue表示跳出本次循環;

break表示退出當前循環;

四、兩個對象值相同(x.equals(y)==true),但是卻有不同的hashcode,這句話對不對?

不對,如果x.equals(y)==true,那麼x、y的hashcode應該相同。

Java對於hashcode和equals是這樣規定的:

  1. 如果兩個對象相同(equals),那麼他們的hashcode一定相同;

  2. 如果兩個對象的hashcode相同,那麼他們的值(equals)不一定相同;

如果違反了上述的規則,就會導致Set集合中出現重複的對象,同時增加新元素的性能大大下降,因爲hash碰撞的機率急劇上升

五、那麼爲什麼重寫equals的時候要重寫hashcode呢? 

因爲從源碼上看,hashCode是native方法,讀取的是內存地址。

public native int hashCode();

而equals方法以String的源碼爲例

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

它是使用==的方式,判斷兩個對象是否相同,如果不是一個對象,然後再判斷String裏面的值是否相同。

大家都知道,hashCode的查詢複雜度是O(1),而equals的複雜度要看equals方法的具體實現,但普遍來講,equals的複雜度要比hashCode查詢慢。

所以,在同時重寫了equals和hashCode方法之後,我們就可以先對hashcode進行比較,當hashcode相等的時候再比較equals,這樣能對性能有較大的提升。

但是也要注意的是,hashcode方法主要使用場景是hashSet和hashMap,這兩個實現類需要對hashcode進行判斷,將值放入到對應的位置中。此時如果不重寫hashcode方法,就容易產生hashSet中存在重複對象的可能。其餘場景其實只重寫equals問題也不大。

但是爲了確保程序的正確和穩定性,我們建議在重寫equals方法的同時,重寫hashcode方法。

六、是否可以繼承String?

String本身是fianl修飾的類,不可以繼承

public final class String

七、java中對象作爲參數,是值傳遞還是引用傳遞?

答:值傳遞

java中只有值傳遞:

  • 基本類型:值傳遞

  • 引用類型:地址值傳遞

當對象作爲參數進行傳遞的時候,傳遞過去的都是副本:

  • 基本類型傳遞的是值得拷貝,不管副本如何變化,原有的值都不會有變化;

  • 引用類型傳遞的是引用的地址值,有可能被影響;

  • String是特殊的引用類型,因爲它是final修飾的,具有不可變性,所以不管怎麼傳遞,返回的String類型對象還是最初傳遞過去的值;

八、重載和重寫的區別?

重載和重寫都是多態的具體實現方式,只是重載時編譯時多態,重寫是運行時多態;重載需要有不同的參數列表,而重寫要發生在子類和父類之間,兩者有相同的方法名稱,相同的參數列表,相同的返回類型。

重載的規則:

  1. 方法名一致,參數的順序、個數、類型不同;

  2. 重載和返回值無關,存在於同類中;

  3. 可以拋出不同的異常,有不同的修飾符;

重寫的規則:

  1. 參數列表必須完全與重寫的方法一致,返回類型也必須一致;

  2. 構造方法、final方法、static方法不能被重寫,但是這些可以重寫聲明(在子類中“重寫”該方法,但是不加@override註解);

  3. 訪問權限不能比父類的訪問權限更低;

九、爲什麼函數不能根據返回類型來重載?

該題來自華爲面試題。

參考如下代碼

當我要調用max(1,2)時,對於上述兩個方法是無法確認我要具體調用哪個方法的,這樣違反了對方法調用的唯一性,造成的結果就是程序產生意想不到的效果,甚至崩潰。

並且函數的返回值,只是作爲函數運行之後的一種狀態描述,目的是產出一個和其他方法之間進行通信的標識,並不能將這個標識作爲是否能重載的依據。

十、一個char類型的變量能否存儲一個漢字?

可以。

我們先補充一下相關的知識:

1字節=8btye

1英文字母=1字節,1漢字=2字節(ASCLL、Unicode編碼)

在UTF-8編碼下,1漢字=3字節

而1個char類型變量佔2個字節,作爲Unicode編碼的漢字來講,是可以存儲的,也就是我們的答案,但是某些不包含在Unicode編碼中,使用UTF-8編碼的漢字,是不能用char類型變量表示的。但是補充來講,在JVM內部是使用Unicode作爲默認編碼,Unicode使用2個字節表示一個漢字,那麼char類型就可以用存儲一個漢字

十一、抽象類(Abstract Class)和接口(Inteface)有什麼異同?

不同:

抽象類:

  1. 抽象類中可以定義構造器;

  2. 可以有抽象方法和具體方法;

  3. 抽象類中成員可以使public、private、protected和默認方法;

  4. 抽象類可以定義成員變量;

  5. 抽象類必須用abstract聲明,但是抽象類中未必要有抽象方法;

  6. 抽象類中可以包含靜態方法;

  7. 一個類只能繼承一個抽象類;

接口:

  1. 接口中不能定義構造器;

  2. 接口的方法必須全部都是抽象方法;

  3. 接口的成員必須全部都是public的;

  4. 接口中定義的成員變量實際上都是常量;

  5. 接口中不能有靜態方法;

  6. 一個類可以實現多個接口;

相同:

  1. 不能夠被實例化;

  2. 可以將抽象類和接口類型作爲引用類型;

  3. 一個類如果繼承了抽象類或者實現了接口,要對其中全部的抽象方法進行實現,否則該類仍需要被聲明爲抽象類;

十二、靜態變量和實例變量的區別

靜態變量:使用static進行修飾,屬於類變量,存放在棧中,是可以被共享的變量;

實例變量:必須依存某個已經初始化的對象才能進行訪問;

十三、==和equals的區別

==對於基本類型來講,比較的是基本類型的值,對於引用類型來講,比較的是引用類型的地址的值

equals不能用來比較基本類型,對於引用類型,比較的是兩個引用類型的內容是否相同

JAVA中的多態

一、java中多態的實現機制是什麼?

多態是指程序中定義的引用變量所指向的具體類型和通過該引用變量發出的方法調用在編譯的時候並不確定,而是在程序運行期間才確定,即一個引用變量到底會指向哪一個類的實例對象,該引用變量發出的方法調用到底是哪一個類中的方法,必須在程序運行期間才能決定!

靠的是父類或接口定義的引用變量可以指向子類或具體實現類的實例對象,而程序調用的方法在運行期才動態綁定,就是引用變量所指向的具體實例對象的方法,也就是內存里正在運行的那個對象的方法,而不是引用變量的類型中定義的方法。

JAVA的異常處理

一、Java中異常分爲哪幾類?

分爲編譯時異常(強制性異常),CheckedException和運行時異常(非強制性異常)RuntimeException。對於編譯時異常要進行顯式處理,否則會導致編譯不通過。

處理異常分爲兩種情況:

  1. 對於清楚該如何處理的異常使用try..catch進行捕獲;

  2. 對於不知道該如何處理的異常使用throws在方法聲明的時候進行拋出;

二、try、catch、finally執行的優先級

try包裹的方法中一旦出現異常,就會走到catch的異常捕獲方法中,但是如果有finally方法,在異常方法返回之前,一定要先執行finally裏面的方法。舉例如下

由於第3行除數爲零,直接跳轉到catch方法中,在catch的return命令之前要先執行finally裏面的方法,所以最終返回結果是3。如果finally裏面只是關閉流的操作,不進行返回的話,最終的返回結果就應該是2。

三、Error和Exception的區別

Error和Exception的父類都是Throwable類,他們的區別如下:

Error一般指虛擬機相關的異常,如系統崩潰、虛擬機錯誤、內存不足、方法調用棧溢出等。這類錯誤會直接導致程序中斷,僅靠程序本身無法恢復和預防,遇到這樣的錯誤,建議程序終止。

Exception分爲運行時異常(RuntimeException)和編譯時異常(CheckedException),運行時異常如ArithmeticException、IllegalArgumentException等,編譯能通過,但是一旦遇到這種異常程序就終止了 ,程序不會處理運行時異常;而編譯時異常可以使用try catch或者throws進行異常處理。

四、寫出最常見的5個編譯時異常

  1. java.lang.NullPointException 空指針異常;出現原因:調用了未初始化的對象或是不存在的對象;

  1. java.lang.ClassNotFoundException 指定類找不到;出現原因:類名和路徑加載錯誤;

  2. java.lang.NumberFormatException 字符串轉換爲數字異常;出現原因:字符串中出現非數字類型字符;

  3. java.lang.IndexOutOfBoundsException 數組下標越界異常;出現原因:訪問數組對象下標超過本身數組長度;

  4. java.lang.IllegalArgumentException 方法參數傳遞錯誤;

  5. java.lang.ClassCastException 類轉換異常;出現原因:類之間不能進行強制轉換;

  6. java.lang.NoClassDefFoundException 未找到定義類;

  7. SQLException SQL編寫錯誤;

  8. java.lang.InstantiationException 實例化異常;

  9. java.lang.NoSuchMethodException 未找到方法異常;

五、throw和throws的區別

throw:

  1. throw用在方法體內,表示拋出異常,由方法體內的語句處理;

  2. throw拋出的一般是一個異常實例;

throws:

  1. 用在方法聲明後面,表示如果存在異常,由方法的調用者進行異常處理;

  2. throws拋出某種異常類型,讓調用者清楚使用何種方法進行異常處理;

  3. throws表示一種可能性,並不代表異常會發生;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章