每日一面系列之Java基礎(上)

1.你知道運算符&和&&,|和||的區別嗎?(考察短路運算符和位運算)

&按位與操作,只有對應的兩個二進制數都爲1的時候,結果才爲1。
例:1 & 1 = 1,1 & 0 = 0,0 & 1 = 0,0 & 0 = 0
|按位或操作,只要對應的兩個二進制數中其中一個爲1的時候,結果就爲1。
例:1 | 1 = 1,1 | 0 = 1,0 | 1 = 1,0 | 0 = 0

&和&&都可以表達和(並且)的意思,區別在於使用&時,兩邊都要參與運算,而使用&&的時候,只要左邊是false右邊就不會參與運算,判斷語句中推薦使用&&,效率更高。

|和||都可以表達或(或者)的意思,區別在於使用|時,兩邊都要參與運算,而使用||的時候,只要左邊是true右邊就不會參與運算。因此&&和||被稱爲短路運算符。

2.計算2乘以8最有效的方法是什麼?(考察位運算)

將一個數左移n位,相當於乘以2的n次方,位運算是CPU直接支持的,所以效率比較高。2<<3。

常見的JDK源碼中HashMap的初始化容量爲16,具體計算如下:
int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
1左移4位也就是10000,轉化爲十進制就是16,直接以二進制進行計算,運算效率更高。

3.講一下Java數據類型分類。(考察Java數據類型的劃分)

基本數據類型:byte、short、int、long、float、double、char、boolean
引用數據類型:其他的都是引用數據類型,包括自己創建的對象。(String和Enum是引用數據類型)

4.==和equals有什麼區別?(考察值與內存地址的比較)

==比較兩個對象的內存地址是否相等,也就是判斷兩個對象是否爲同一個對象,基本數據類型使用它比較的是值,引用數據類型使用它比較比較的是內存地址。

equals也可以判斷兩個對象是否相等,如果沒有重寫equals方法,那麼通過equals方法比較兩個對象時,等同於使用“==”比較這兩個對象。如果重寫了equals方法,一般我們都會重寫equals方法來比較兩個對象的值(內容),如果值相等則返回true,表示這兩個對象相等。

舉個例子:

public class test1 {
    public static void main(String[] args) {
        String a = new String("ab"); // a 爲一個引用
        String b = new String("ab"); // b爲另一個引用,對象的內容一樣
        String aa = "ab"; // 放在常量池中
        String bb = "ab"; // 從常量池中查找
        if (aa == bb) // true
            System.out.println("aa==bb");
        if (a == b) // false,非同一對象
            System.out.println("a==b");
        if (a.equals(b)) // true
            System.out.println("aEQb");
        if (42 == 42.0) { // true
            System.out.println("true");
        }
    }
}

說明:String類中的equals方法是被重寫過的,因爲object中的equals方法比較的是兩個對象的內存地址,而String中的equals方法比較的是兩個對象的值(內容)。

5.下面代碼中的try-catch-finally語句,try裏面有return,finally裏面也有return,那麼執行結果是什麼?爲什麼?(考察try-catch-finally語句塊的執行)

public static int test1() {
 	int a = 1;
 	try {
 		System.out.println(a / 0);
	 	a = 2;
 	} catch (ArithmeticException e) {
	 	a = 3;
 		return a;
 	} finally {
 		a = 4;
 	}
 	return a;
 }
//執行結果爲3
 public static int test2() {
 	int a = 1;
 	try {
 		System.out.println(a / 0);
 		a = 2;
 	} catch (ArithmeticException e) {
 		a = 3;
 		return a;
 	} finally {
		 a = 4;
 		return a;
	 }
 }
 //執行結果爲4

在執行try-catch中的return之前一定會先執行finally中的代碼(如果finally存在),如果finally中有return語句,就會直接執行finally中的return,如果finally中沒有return(return在try或者catch中),則會先確定return返回值,然後再執行finally中的代碼,最後再執行return。

7.講一下重寫與重載的區別,構造器Constructor是否可以被override?(考察重載與重寫)

重載:發生在同一個類中,方法名必須相同,參數列表不同,返回值和訪問修飾符可以不同,發生在編譯時。

重寫:發生在父子類中,方法名、參數列表必須相同,返回值範圍必須小於等於父類,拋出異常範圍必須小於等於父類,訪問修飾符範圍必須大於等於父類,如果父類方法訪問修飾符爲private則子類不可以重寫該方法。

因爲父類的私有屬性和構造方法不能被繼承,所以Constructor不可以被override(重寫),但是可以被overload(重載),所以可以看到一個類中有多個構造函數的情況。

8.談談Java面向對象的四大特性。(考察對面向對象OOP思想的理解)

抽象:關鍵詞abstract修飾的類叫做抽象類,abstract聲明的方法叫做抽象方法,一個類包含一個或多個抽象方法,則該類就是抽象類,抽象方法屬於一種特殊的方法,只有一個聲明,沒有方法體。

封裝:封裝就是把一個對象的屬性私有化,同時提供一個方法讓外界訪問可以訪問的屬性,如果屬性不想背外界訪問,可以不提供外界訪問屬性的方法。但是一個類如果沒有給外界提供訪問任何屬性的方法,那麼這個類也就沒有了存在的意義。

繼承:繼承就是使用現有的類(父類)定義新類(子類),子類可以使用父類的方法、屬性,子類也可以增加新的方法、屬性。但是不能選擇性的繼承父類,使用繼承能夠讓我們更加方便的是同以前的代碼,繼承擁有以下3個重要的特性:

  1. 子類擁有父類所有的屬性和方法(包括私有屬性和私有方法),但是父類中私有的屬性和方法子類是不可以訪問的,只有擁有權。
  2. 子類可以擁有自己的屬性和方法,可以對父類進行擴展。
  3. 子類可以使用自己的方式實現父類的方法(重寫)。

多態:多態是同一個行爲具有不同表現形式和形態的能力,具體體現就是同一個接口使用不同的實例而執行不同的操作。多態存在的三個必要條件是繼承、重寫、父類引用只想子類對象。Java中有兩種方式可以實現多態:繼承(多個子類對父類的同一個方法進行重寫)和接口(實現接口並且覆蓋接口中的同一個方法)。

9.接口和抽象類的區別是什麼?抽象類中必須有抽象方法嗎?抽象類能使用final修飾嗎?(考察接口與抽象類)

接口與抽象類的區別:

  1. 接口的方法默認是public,接口中的方法不能有具體的實現(Java8中可以再接口中定義方法的默認實現,也就是可以定義靜態方法,外界可以直接使用接口名進行調用,實現類和實現是不可以調用的,如果同時實現兩個接口,接口中定義了一樣的默認方法,則必須重寫,不然會報錯),抽象類中可以有非抽象的方法。
  2. 接口中的實例變量默認是final修飾的,抽象類中則不一定。
  3. 一個類可以實現多個接口,但是最多實現(繼承)一個抽象類。
  4. 一個類如果實現一個接口,需要實現該接口的所有方法,而抽象類不一定。
  5. 接口不能用new關鍵字實例化,但是可以聲明,必須引用一個實現該接口的對象。從設計層面來說,抽象是對類的抽象,是一種模板設計,而接口是對行爲的一種抽象,是對行爲的規範。

抽象類不一定包含抽象方法,但是有抽象方法的類一定是抽象類。

抽象類不能是用final修飾,被final修飾的類不可以被繼承,final類中的成員方法都會被隱式的指定爲final方法,這就違背了抽象類存在的意義。

10.String str = new String(“Jesse”);創建了幾個對象?String str1 = "abcd"與String str2 = new String(“abcd”)一樣嗎?str1和str2相等嗎?(考察對象的創建)

問題1:
如果常量池中存在“Jesse”這個String對象,那麼就在堆中創建String對象str,然後指向“Jesse”對象,一共創建了一個對象。
如果常量池中不存在“Jesse”這個String對象,那麼先在常量池中創建String對象“Jesse”,然後再堆中創建一個String對象str,再指向“Jesse”對象,一共創建了兩個對象。

問題2:
這兩種不同的創建方式是有一定的差別的。

第一種方式:可能創建一個或者不創建對象。如果“abcd”這個String對象再常量池中不存在,則會在常量池中創建一個String對象“abcd”,然後str1指向“abcd”的內存地址,無論以後用這種方式創建多少個值爲”abcd”的字符串對象,始終只有一個內存地址被分配,之後的都是String的拷貝,Java中稱爲“字符串駐留”,所有的字符串常量都會在編譯之後自動地駐留。

第二種方式:至少會創建一個對象,也可能是兩個對象。因爲使用到了new關鍵字,所以必然會在堆中創建一個String對象“str2”,同時會看“abcd”這個String在不在常量池中,如果在就直接指向,如果不在就先創建再指向。

問題3:
str1和str2不相等。因爲一個是堆內存中的String對象,一個是常量池中的String對象,內存地址不同。

11.String、StringBuffer和StringBuilder的區別是什麼?分別在那些場景下使用?String爲什麼是不可變的?(考察字符串相關構建類的使用和區別)

問題1:

  1. String對象是不可變的,每次對String類型對象進行改變的時候都會創建一個新的String對象,然後將指針指向新的String對象,而StringBuffer和StringBuilder是可變的,每次改變都是對對象本身進行修改。
  2. StringBuffer對方法或者調用它的方法加了同步鎖(synchronized),所以是線程安全的。
  3. StringBuilder不需要加鎖,線程不安全,效率更高。

問題2:
操作少量的數據使用String。
單線程下操作字符串緩衝區下大量數據使用StringBuilder。
多線程下操作字符串緩衝區下大量數據使用StringBuffer。

問題3:String類中使用final關鍵字修飾字符數組來保存字符串。而StringBuilder和StringBuffer都是繼承與AbstractStringBuilder類,AbstractStringBuilder類中的字符串數組是沒有被final修飾的,所以StringBuffer和StringBuilder是可變的。

12.是否瞭解JDK8中接口的新特性?(考察JDK8新特性)

1. 接口中可以有靜態方法,但是方法必須有實現體,該方法屬於接口,可以使用接口名調用該方法。
2. 接口中新增default關鍵字修飾的方法,default方法只能定義在接口中,子類或者子接口中可以重新default方法且必須有方法體。
3. 父接口中的default方法如果在子類或者子接口中被重寫,那麼子類或者子接口調用該方法時以重寫的方法爲準。
4. 本類、接口如果沒有重寫父類的default方法,則在調用default方法的時候,使用父類(接口)中定義的default方法。

13.什麼是hashCode?你重寫過hashCode和equals嗎?爲什麼重寫equals方法時必須重寫hashCode方法?(考察hashCode和equals的關係)

問題1:
hashCode()方法的作用就是獲取哈希碼,也成爲散列碼,該方法的返回值是一個int類型的整數,這個哈希碼的作用是確定該對象再哈希表中的索引位置。

問題2&問題3:
如果兩個對象相等,則hashCode一定是相等的。對兩個相等的對象調用equals方法返回結果爲true。兩個具有相同hashCode的對象不一定相等,因爲不同的對象也可能會產生相同的hashCode,這是概率性問題,hashCode的默認行爲是對堆上的對象產生獨特值,如果沒有重寫hashCode方法,則該class的兩個對象無論如何都不會相等,即使這兩個對象指向相同的數據。說白了就是爲了保證equals比較之後相同的兩個對象的hashcode值也相等。
**

14.什麼是反射機制?反射機制的有缺點是什麼?反射機制的應用場景有哪些?(考察Java反射機制)

問題1:
Java反射機制是指在運行狀態中,對於任意一個類,都能夠知道它的屬性和方法,對於任意一個對象,都能夠調用它的任意屬性和方法,這種動態獲取類信息以及調用對象方法的功能在Java語音中成爲反射機制。

問題2:
優點:運行期類型的判斷,動態加載類,提高代碼的靈活性。
缺點:反射相等於一系列解釋性操作,是直接通知JVM需要做什麼事情,要比直接執行的Java代碼再性能上面慢很多。

問題3:
反射是框架設計的靈魂,在日常開發中基本上很少會直接用到反射。除了日常所用的框架用到了反射,在我們進行模塊化開發,通過反射調用對應字節碼,動態代理設計模式也用到了反射。比如我們在使用JDBC連接數據庫時使用Class.forName()通過反射加載數據庫驅動程序,Spring框架的XML哦誒之模式也用到了反射。

15.什麼是值傳遞?什麼是引用傳遞?爲什麼Java中只有值傳遞?(考察對象的傳遞)

問題1&問題2:
值傳遞:在調用函數時將實際參數的值複製一份傳遞到函數中,函數中接受到的參數只是實際參數的一個副本,這樣再函數中如果對參數進行了修改,也不會影響實際參數的值。

引用傳遞:在調用函數時將實際參數的內存地址傳遞給函數,這樣再函數中如果對參數進行修改,就會影響實際參數的值。

總結:值傳遞就是接收方接收到的是調用者提供的值,引用傳遞就是接收方接受到的是調用者提供的參數內存地址,一個方法可以修改傳遞引用鎖對應的變量值,不能修改傳遞值對用的變量值。

問題3:
Java程序設計語言總是按照值傳遞的方式來傳遞參數,也就是說方法得到的參數是實際參數值的一個拷貝,方法不能修改傳遞給它的參數的實際值。在Java中對對象的引用實際上值對對象的值的傳遞。

在Java中方法參數有以下三種情況:

  1. 一個方法不能修改一個基本數據類型的參數。
  2. 一個方法可以改變一個對象參數的狀態。
  3. 一個方法不能讓對象參數引用一個新的對象。

16.爲什麼從上家公司離職?(一般HR必問)

  1. 千萬不能說上家公司的不好,比如常加班、不漲工資、公司制度混亂等負面情緒。
  2. 可以說搬家了,上家公司距離比較遠。
  3. 想追求更高的生活品質。
  4. 對自己有更高的要求,希望自己能夠在新的平臺得到提升。
  5. 個人職業規劃,想在某個領域(傳統CRM、電商、ERP項目等)發展等。

每日一面,終成麪霸!

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