1. 程式人生 > >JAVA面試寶典-基礎篇(二)

JAVA面試寶典-基礎篇(二)

11"=="equals方法究竟有什麼區別?

(單獨把一個東西說清楚,然後再說清楚另一個,這樣,它們的區別自然就出來了,混在一起說,則很難說清楚)

==操作符專門用來比較兩個變數的值是否相等,也就是用於比較變數所對應的記憶體中所儲存的數值是否相同,要比較兩個基本型別的資料或兩個引用變數是否相等,只能用==操作符。

如果一個變數指向的資料是物件型別的,那麼,這時候涉及了兩塊記憶體,物件本身佔用一塊記憶體(堆記憶體),變數也佔用一塊記憶體,例如Objet obj = new Object();變數obj是一個記憶體,new Object()是另一個記憶體,此時,變數obj所對應的記憶體中儲存的數值就是物件佔用的那塊記憶體的首地址。對於指向物件型別的變數,如果要比較兩個變數是否指向同一個物件,即要看這兩個變數所對應的記憶體中的數值是否相等,這時候就需要用

==操作符進行比較。

equals方法是用於比較兩個獨立物件的內容是否相同,就好比去比較兩個人的長相是否相同,它比較的兩個物件是獨立的。例如,對於下面的程式碼:

String a=new String("foo");

String b=new String("foo");

兩條new語句建立了兩個物件,然後用a,b這兩個變數分別指向了其中一個物件,這是兩個不同的物件,它們的首地址是不同的,即ab中儲存的數值是不相同的,所以,表示式a==b將返回false,而這兩個物件中的內容是相同的,所以,表示式a.equals(b)將返回true

在實際開發中,我們經常要比較傳遞進行來的字串內容是否等,例如,

String input = …;input.equals(“quit”),許多人稍不注意就使用==進行比較了,這是錯誤的,隨便從網上找幾個專案實戰的教學視訊看看,裡面就有大量這樣的錯誤。記住,字串的比較基本上都是使用equals方法。

如果一個類沒有自己定義equals方法,那麼它將繼承Object類的equals方法,Object類的equals方法的實現程式碼如下:

boolean equals(Object o){

return this==o;

}

這說明,如果一個類沒有自己定義equals方法,它預設的equals方法(從Object 類繼承的)就是使用==操作符,也是在比較兩個變數指向的物件是否是同一物件,這時候使用

equals和使用==會得到同樣的結果,如果比較的是兩個獨立的物件則總返回false。如果你編寫的類希望能夠比較該類建立的兩個例項物件的內容是否相同,那麼你必須覆蓋equals方法,由你自己寫程式碼來決定在什麼情況即可認為兩個物件的內容是相同的。

12、靜態變數和例項變數的區別?

在語法定義上的區別:靜態變數前要加static關鍵字,而例項變數前則不加。

在程式執行時的區別:例項變數屬於某個物件的屬性,必須建立了例項物件,其中的例項變數才會被分配空間,才能使用這個例項變數。靜態變數不屬於某個例項物件,而是屬於類,所以也稱為類變數,只要程式載入了類的位元組碼,不用建立任何例項物件,靜態變數就會被分配空間,靜態變數就可以被使用了。總之,例項變數必須建立物件後才可以通過這個物件來使用,靜態變數則可以直接使用類名來引用。

例如,對於下面的程式,無論建立多少個例項物件,永遠都只分配了一個staticVar變數,並且每建立一個例項物件,這個staticVar就會加1;但是,每建立一個例項物件,就會分配一個instanceVar,即可能分配多個instanceVar,並且每個instanceVar的值都只自加了1次。

public class VariantTest{

          publicstatic int staticVar = 0;

          publicint instanceVar = 0;

          publicVariantTest(){

                  staticVar++;

                  instanceVar++;

                  System.out.println(“staticVar=”+ staticVar + ”,instanceVar=” + instanceVar);

          }

}

備註:這個解答除了說清楚兩者的區別外,最後還用一個具體的應用例子來說明兩者的差異,體現了自己有很好的解說問題和設計案例的能力,思維敏捷,超過一般程式設計師,有寫作能力!

13、是否可以從一個static方法內部發出對非static方法的呼叫?

不可以。因為非static方法是要與物件關聯在一起的,必須建立一個物件後,才可以在該物件上進行方法呼叫,而static方法呼叫時不需要建立物件,可以直接呼叫。也就是說,當一個static方法被呼叫時,可能還沒有建立任何例項物件,如果從一個static方法中發出對非static方法的呼叫,那個非static方法是關聯到哪個物件上的呢?這個邏輯無法成立,所以,一個static方法內部發出對非static方法的呼叫。

14Integerint的區別

intjava提供的8種原始資料型別之一。Java為每個原始型別提供了封裝類,Integerjavaint提供的封裝類。int的預設值為0,而Integer的預設值為null,即Integer可以區分出未賦值和值為0的區別,int則無法表達出未賦值的情況,例如,要想表達出沒有參加考試和考試成績為0的區別,則只能使用Integer。在JSP開發中,Integer的預設為null,所以用el表示式在文字框中顯示時,值為空白字串,而int預設的預設值為0,所以用el表示式在文字框中顯示時,結果為0,所以,int不適合作為web層的表單資料的型別。

Hibernate中,如果將OID定義為Integer型別,那麼Hibernate就可以根據其值是否為null而判斷一個物件是否是臨時的,如果將OID定義為了int型別,還需要在hbm對映檔案中設定其unsaved-value屬性為0

另外,Integer提供了多個與整數相關的操作方法,例如,將一個字串轉換成整數,Integer中還定義了表示整數的最大值和最小值的常量。

15Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

Math類中提供了三個與取整有關的方法:ceilfloorround,這些方法的作用與它們的英文名稱的含義相對應,例如,ceil的英文意義是天花板,該方法就表示向上取整,Math.ceil(11.3)的結果為12,Math.ceil(-11.3)的結果是-11floor的英文意義是地板,該方法就表示向下取整,Math.ceil(11.6)的結果為11,Math.ceil(-11.6)的結果是-12;最難掌握的是round方法,它表示四捨五入,演算法為Math.floor(x+0.5),即將原來的數字加上0.5後再向下取整,所以,Math.round(11.5)的結果為12Math.round(-11.5)的結果為-11

16、下面的程式碼有什麼不妥之處?

1.if(username.equals(“zxx”){}

    2.  int  x = 1;

          return x==1?true:false;

17、請說出作用域publicprivateprotected,以及不寫時的區別

這四個作用域的可見範圍如下表所示。

說明:如果在修飾的元素上面沒有寫任何訪問修飾符,則表示friendly

作用域    當前類同一package 子孫類其他package

public   √     √          √       √

protected √     √          √      ×

friendly  √     √          ×      ×

private   √     ×          ×      × 

備註:只要記住了有4種訪問許可權,4個訪問範圍,然後將全選和範圍在水平和垂直方向上分別按排從小到大或從大到小的順序排列,就很容易畫出上面的圖了。

18OverloadOverride的區別。Overloaded的方法是否可以改變返回值的型別?

Overload是過載的意思,Override是覆蓋的意思,也就是重寫。

過載Overload表示同一個類中可以有多個名稱相同的方法,但這些方法的引數列表各不相同(即引數個數或型別不同)。

重寫Override表示子類中的方法可以與父類中的某個方法的名稱和引數完全相同,通過子類建立的例項物件呼叫這個方法時,將呼叫子類中的定義方法,這相當於把父類中定義的那個完全相同的方法給覆蓋了,這也是面向物件程式設計的多型性的一種表現。子類覆蓋父類的方法時,只能比父類丟擲更少的異常,或者是丟擲父類丟擲的異常的子異常,因為子類可以解決父類的一些問題,不能比父類有更多的問題。子類方法的訪問許可權只能比父類的更大,不能更小。如果父類的方法是private型別,那麼,子類則不存在覆蓋的限制,相當於子類中增加了一個全新的方法。

至於Overloaded的方法是否可以改變返回值的型別這個問題,要看你倒底想問什麼呢?這個題目很模糊。如果幾個Overloaded的方法的引數列表不一樣,它們的返回者型別當然也可以不一樣。但我估計你想問的問題是:如果兩個方法的引數列表完全一樣,是否可以讓它們的返回值不同來實現過載Overload。這是不行的,我們可以用反證法來說明這個問題,因為我們有時候呼叫一個方法時也可以不定義返回結果變數,即不要關心其返回結果,例如,我們呼叫map.remove(key)方法時,雖然remove方法有返回值,但是我們通常都不會定義接收返回結果的變數,這時候假設該類中有兩個名稱和引數列表完全相同的方法,僅僅是返回型別不同,java就無法確定程式設計者倒底是想呼叫哪個方法了,因為它無法通過返回結果型別來判斷。

override可以翻譯為覆蓋,從字面就可以知道,它是覆蓋了一個方法並且對其重寫,以求達到不同的作用。對我們來說最熟悉的覆蓋就是對介面方法的實現,在介面中一般只是對方法進行了宣告,而我們在實現時,就需要實現介面宣告的所有方法。除了這個典型的用法以外,我們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意以下的幾點:

1、覆蓋的方法的標誌必須要和被覆蓋的方法的標誌完全匹配,才能達到覆蓋的效果;

2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;

3、覆蓋的方法所丟擲的異常必須和被覆蓋方法的所丟擲的異常一致,或者是其子類;

4、被覆蓋的方法不能為private,否則在其子類中只是新定義了一個方法,並沒有對其進行覆蓋。

overload對我們來說可能比較熟悉,可以翻譯為過載,它是指我們可以定義一些名稱相同的方法,通過定義不同的輸入引數來區分這些方法,然後再呼叫時,VM就會根據不同的引數樣式,來選擇合適的方法執行。在使用過載要注意以下的幾點:

1、在使用過載時只能通過不同的引數樣式。例如,不同的引數型別,不同的引數個數,不同的引數順序(當然,同一方法內的幾個引數型別必須不一樣,例如可以是fun(int,float),但是不能為fun(int,int));

2、不能通過訪問許可權、返回型別、丟擲的異常進行過載;

3、方法的異常型別和數目不會對過載造成影響;

4、對於繼承來說,如果某一方法在父類中是訪問許可權是priavte,那麼就不能在子類對其進行過載,如果定義的話,也只是定義了一個新方法,而不會達到過載的效果。

19、構造器Constructor是否可被override?

構造器Constructor不能被繼承,因此不能重寫Override,但可以被過載Overload

20、介面是否可繼承介面抽象類是否可實現(implements)介面抽象類是否可繼承具體類(concrete class)? 抽象類中是否可以有靜態的main方法?

介面可以繼承介面。抽象類可以實現(implements)介面,抽象類是否可繼承具體類。抽象類中可以有靜態的main方法。

備註:只要明白了介面和抽象類的本質和作用,這些問題都很好回答,你想想,如果你是java語言的設計者,你是否會提供這樣的支援,如果不提供的話,有什麼理由嗎?如果你沒有道理不提供,那答案就是肯定的了。

 只有記住抽象類與普通類的唯一區別就是不能建立例項物件和允許有abstract方法。