【最新Android高級面試知識點--Java基礎】

2020年開年不利,大家都過得不容易。我們大家都辛苦了!
通過這次的疫情,使我更加直觀也更進一步的理解了,何謂“命運共同體”。
如果你現在有工作,那麼恭喜你。你要做的就是少點抱怨,更加努力的工作,把工作做好,多存點錢。
如果你正在找工作,那麼我想說的是:不要急,選好自己心儀的行業,心儀的公司,好好準備面試,向它發起挑戰。只要你真正努力了,真正問心無愧了,那麼勝利終將屬於你!!

轉載請說明出處

2020年Android高級面試知識點乾貨分享系列,我將分爲兩大篇(Java基礎篇Android開發篇),多小節的形式進行連載(由於要對筆記進行排版整理)。這些完全都是我個人今年在找工作時的面試準備(知識點筆記),現在分享出來,希望能對你有一點點幫助(如果有些知識點我沒有到位的,或者存在錯誤的,歡迎留言指正。我會持續更新)。

《Java篇》

一、== 與 equals()的區別

對於這兩者的區別,想深刻理解的,得對Java類加載機制,JVM內存模型,彙編指令集等都有個瞭解。可以自己寫個java測試類,利用javac編譯成class文件,然後再利用javap -c xxx來對字節碼進行反彙編,查看代碼的執行過程。從而從根源上搞懂==與equals的區別。

$1.1、==

比較操作符,比較的是兩個操作數變量的值是否相等。

  • 當比較的是int 基本類型時,比較值;
  • 當變量爲引用類型時,比較的是引用類型變量的內存地址。

下面以引用類型爲例看下==的執行過程:

public class Test {

    public static void main(String[] args) {
        String var1 = "Hello";
        String var2 = "World";
        boolean result = (var1 == var2);
        System.out.println("result=" + result);
    }
}

下面利用javap -c Test對其進行反彙編,結果信息如下:

Compiled from "Test.java"
public class ext.sunny.com.activitylifedemo.Test {
//構造方法代碼塊執行
  public ext.sunny.com.activitylifedemo.Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":
()V
       4: return

  public static void main(java.lang.String[]);
    Code:
    //ldc:指令,用於將int、float、String類型常量從常量池中壓到棧頂
    //這裏指將字符串常量"Hello",壓入棧頂
       0: ldc           #2                  // String Hello
       //astore_1:pop出棧頂的引用值,並且將它賦值給變量var1
       2: astore_1
       //ldc:將字符常量“World"從常量池中壓到棧頂
       3: ldc           #3                  // String World
       //astroe_2:與上面一樣,pop出棧頂的引用值,並且將它賦值給變量var2
       5: astore_2
       //aload指令:加載本地變量,並壓入操作數棧
       //aload_1:將var1變量的引用值壓入操作數棧
       //aload_2:將var2變量的引用值壓入操作數棧
       6: aload_1
       7: aload_2
       //if_acmpne:有條件轉移指令。可以理解像java中的if條件語句
       //如果兩個對象引用不相等,則跳轉
       //iconst_0、iconst_1:表示將int類型常量0與1壓入棧
       8: if_acmpne     15
      11: iconst_1
      12: goto          16
      15: iconst_0
      //istore_3:將局部變量(這裏指上面條件指令後的結果)存入3變量,即result中。
      16: istore_3
////下面就是System.out.print()打印輸出的執行過程了。
      17: getstatic     #4                  // Field java/lang/System.out:Ljava/
io/PrintStream;
      20: new           #5                  // class java/lang/StringBuilder
      23: dup
      24: invokespecial #6                  // Method java/lang/StringBuilder."<
init>":()V
      27: ldc           #7                  // String result=
      29: invokevirtual #8                  // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      32: iload_3
      33: invokevirtual #9                  // Method java/lang/StringBuilder.ap
pend:(Z)Ljava/lang/StringBuilder;
      36: invokevirtual #10                 // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
      39: invokevirtual #11                 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
      42: return
}

$1.2、equals()

爲Object類中的方法:

public boolean equals(Object obj) {
    return (this == obj);
}

注意點:

  • equals()不能比較基本數據類型;
  • 如果equals()比較的對象沒有複寫超類的equals()方法,則比較的是內存地址;
  • 如果比較的對象有複寫equals()方法,比如String,且有自己的比較規則,則按照自己的比較規則進行,比如String對象比較的是char字符值。

擴展】:
在使用HashMap時,如果其Key你是用的引用對象,爲了避免Hash衝突,此引用對象應該重寫equals()方法,制定自己的比較規則。

二、String、StringBuffer與StringBuilder的區別

這裏主要要理解Java的運行時數據區:
PC計數器、棧、本地方法棧、方法區(常量池屬於裏面的一塊特殊內存空間)、堆

$2.1、String

分兩種:字符串常量、對象

  • String是字符串常量,則定義後其值存放在常量池,不可變(底層採用字符數組來存儲,且是final,因此不可變);
  • 如果是用new關鍵字生成出來的String對象則存放在堆中(只是將其引用值賦值給變量存入棧中)。

$2.2、StringBuffer

  • 繼承自AbstractStringBuilder
  • 是線程安全的,因爲裏面的操作方法都用synchronized關鍵字(常用於多線程),同時效率不高
  • 值可變。

$2.3、StringBuilder

  • 繼承自AbstractStringBuilder
  • 非線程安全(無synchronized關鍵字)
  • 值可變
  • 效率比StringBuffer高,常用於單線程操作多個字符串。

備註:
我們在拼接字符串時,會習慣性的使用“+”,其實這個加號我們反彙編(可以參照上面的反彙編代碼)可以發現,它裏面就是new的StringBuilder對象來實現的。且它是每一行遇到+就會生成StringBuilder對象。因此在開發中,如果是很簡單的拼接或者是測試可以用“+”,但其他情況(非多線程下),從效率以及內存上建議使用StringBuilder。

下一小節還是Java篇,我將分享以下面試筆記【Java集合】、【反射與泛型】、【JVM內存模型】

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