Java 基礎面試知識點

Java 基礎知識相關

Java中 == 和 equals 和 hashCode 的區別

對於關係操做符 ==html

  • 若操做數的類型是基本數據類型,則該關係操做符判斷的是左右兩邊操做數的是否相等
  • 若操做數的類型是引用數據類型,則該關係操做符判斷的是左右兩邊操做數的內存地址是否相同。也就是說,若此時返回true,則該操做符做用的必定是同一個對象。

對於使用 equals 方法,內部實現分爲三個步驟:java

  1. 先比較引用是否相同(是否爲同一對象),
  2. 再判斷類型是否一致(是否爲同一類型),
  3. 最後比較內容是否一致

Java 中全部內置的類的 equals 方法的實現步驟均是如此,特別是諸如 Integer,Double 等包裝器類。如如下 String 中的 equals 方法實現android

// String.java 
    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;
    }
複製代碼

hashcode是系統用來快速檢索對象而使用git

equals方法本意是用來判斷引用的對象是否一致github

重寫equals方法和hashcode方法時,equals方法中用到的成員變量也一定會在hashcode方法中用到,只不過前者做爲比較項,後者做爲生成摘要的信息項,本質上所用到的數據是同樣的,從而保證兩者的一致性面試

參考

int、char、long各佔多少字節數

Java 基本類型佔用的字節數安全

  • 1字節: byte , boolean
  • 2字節: short , char
  • 4字節: int , float
  • 8字節: long , double

注:1字節(byte)=8位(bits)網絡

int與integer的區別

  • Integer是int的包裝類,int則是java的一種基本數據類型
  • Integer變量必須實例化後才能使用,而int變量不須要
  • Integer實際是對象的引用,當new一個Integer時,其實是生成一個指針指向此對象;而int則是直接存儲數據值
  • Integer的默認值是null,int的默認值是0
參考

對 Java 多態的理解

多態是指父類的某個方法被子類重寫時,能夠產生本身的功能行爲,同一個操做做用於不一樣對象,能夠有不一樣的解釋,產生不一樣的執行結果。多線程

多態的三個必要條件:併發

  1. 繼承父類。
  2. 重寫父類的方法。
  3. 父類的引用指向子類對象

而後可使用結合里氏替換法則進一步的談理解

里氏替換法則 ---- 全部引用基類的地方必須能透明地使用其子類的對象

  • 子類必須徹底實現父類的方法

注意 在類中調用其餘類時務必要使用父類或接口,若是不能使用父類或接口,則說明類的設計已經違背了LSP原則

注意 若是子類不能完整地實現父類的方法,或者父類的某些方法在子類中已經發生「畸變」,則建議斷開父子繼承關係,採用依賴、彙集、組合等關係代替繼承

  • 子類能夠有本身的個性
  • 覆蓋或實現父類的方法時輸入參數能夠被放大
  • 覆寫或實現父類的方法時輸出結果能夠被縮小

在項目中,採用里氏替換原則時,儘可能避免子類的「個性」,一旦子類有「個性」,這個子類和父類之間的關係就很難調和了, 把子類當作父類使用,子類的「個性」被抹殺——委屈了點;把子類單獨做爲一個業務來使用,則會讓代碼間的耦合關係變得撲朔迷離——缺少類替換的標準

String、StringBuffer、StringBuilder 區別

StringBuffer 和 String 同樣都是用來存儲字符串的,只不過因爲他們內部的實現方式不一樣,致使他們所使用的範圍不一樣,對於 StringBuffer 而言,他在處理字符串時,如果對其進行修改操做,它並不會產生一個新的字符串對象,因此說在內存使用方面它是優於 String 的

StringBuilder 也是一個可變的字符串對象,他與 StringBuffer 不一樣之處就在於它是線程不安全的,基於這點,它的速度通常都比 StringBuffer 快

String 字符串的拼接會被 JVM 解析成 StringBuilder 對象拼接,在這種狀況下 String 的速度比 StringBuffer 的速度快

str +=」b」等同於 str = new StringBuilder(str).append(「b」).toString();

詳解內部類

內部類使得多重繼承的解決方案變得更加完整

使用內部類最吸引人的緣由是:每一個內部類都能獨立地繼承一個(接口的)實現,因此不管外圍類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響

使用內部類才能實現多重繼承

  • 內部類能夠用多個實例,每一個實例都有本身的狀態信息,而且與其餘外圍對象的信息相互獨立。
  • 在單個外圍類中,可讓多個內部類以不一樣的方式實現同一個接口,或者繼承同一個類。
  • 建立內部類對象的時刻並不依賴於外圍類對象的建立。
  • 內部類並無使人迷惑的「is-a」關係,他就是一個獨立的實體。
  • 內部類提供了更好的封裝,除了該外圍類,其餘類都不能訪問。

當咱們在建立某個外圍類的內部類對象時,此時內部類對象一定會捕獲一個指向那個外圍類對象的引用,只要咱們在訪問外圍類的成員時,就會用這個引用來選擇外圍類的成員

成員內部類

在成員內部類中要注意兩點,

  • 成員內部類中不能存在任何 static 的變量和方法
  • 成員內部類是依附於外圍類的,因此只有先建立了外圍類纔可以建立內部類

靜態內部類

靜態內部類與非靜態內部類之間存在一個最大的區別,咱們知道非靜態內部類在編譯完成以後會隱含地保存着一個引用,該引用是指向建立它的外圍內,可是靜態內部類卻沒有。沒有這個引用就意味着:

  • 它的建立是不須要依賴於外圍類的。
  • 它不能使用任何外圍類的非static成員變量和方法。

參考

爲何Java裏的匿名內部類只能訪問final修飾的外部變量?

匿名內部類用法

public class TryUsingAnonymousClass {
    public void useMyInterface() {
        final Integer number = 123;
        System.out.println(number);

        MyInterface myInterface = new MyInterface() {
            @Override
            public void doSomething() {
                System.out.println(number);
            }
        };
        myInterface.doSomething();

        System.out.println(number);
    }
}
複製代碼

編譯後的結果

class TryUsingAnonymousClass$1 implements MyInterface {
    private final TryUsingAnonymousClass this$0;
    private final Integer paramInteger;

    TryUsingAnonymousClass$1(TryUsingAnonymousClass this$0, Integer paramInteger) {
        this.this$0 = this$0;
        this.paramInteger = paramInteger;
    }

    public void doSomething() {
        System.out.println(this.paramInteger);
    }
}
複製代碼

由於匿名內部類最終用會編譯成一個單獨的類,而被該類使用的變量會以構造函數參數的形式傳遞給該類,例如:Integer paramInteger,若是變量 不定義成final的,paramInteger在匿名內部類被能夠被修改,進而形成和外部的paramInteger不一致的問題,爲了不這種不一致的狀況,由於Java 規定匿名內部類只能訪問final修飾的外部變量

抽象類和接口的區別

  1. 默認的方法實現抽象類能夠有默認的方法實現徹底是抽象的。接口根本不存在方法的實現
  2. 實現抽象類使用 extends 關鍵字來繼承抽象類。若是子類不是抽象類的話,它須要提供抽象類中全部聲明的方法的實現。子類使用關鍵字 implements 來實現接口。它須要提供接口中全部聲明的方法的實現。
  3. 抽象類能夠有構造器,而接口不能有構造器
  4. 抽象方法能夠有public、protected和default這些修飾符。接口方法默認修飾符是public。你不可使用其它修飾符。
  5. 抽象類在java語言中所表示的是一種繼承關係,一個子類只能存在一個父類,可是能夠存在多個接口。
  6. 抽象方法比接口速度要快,接口是稍微有點慢的,由於它須要時間去尋找在類中實現的方法。
  7. 若是往抽象類中添加新的方法,你能夠給它提供默認的實現。所以你不須要改變你如今的代碼。 若是你往接口中添加方法,那麼你必須改變實現該接口的類
參考

泛型中 extends 和 super 的區別

父類的靜態方法能不能被子類重寫

靜態方法與靜態成員變量能夠被繼承,可是不能被重寫。它對子類隱藏,所以靜態方法也不能實現多態

進程和線程的區別

進程和線程的主要差異在於它們是不一樣的操做系統資源管理方式。進程有獨立的地址空間,一個進程崩潰後,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不一樣執行路徑。線程有本身的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉,因此多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行而且又要共享某些變量的併發操做,只能用線程,不能用進程。

final, finally, finalize的區別

  • final 用於聲明屬性,方法和類, 分別表示屬性不可變, 方法不可覆蓋, 類不可繼承.

  • finally 是異常處理語句結構的一部分,表示老是執行.

  • finalize 是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,能夠覆蓋此方法提供垃圾收集時的其餘資源回收,例如關閉文件等. JVM不保證此方法總被調用.

參考

Parcelable和Serializable的區別

Serializable是Java中的序列化接口,其使用起來簡單但 是開銷很大,序列化和反序列化過程須要大量I/O操做。而Parcelable是Android中的序列化方式,所以更適合用在Android平臺上,它的缺點就是使用起來稍微麻煩 點,可是它的效率很高,這是Android推薦的序列化方式,所以咱們要首選Parcelable。Parcelable主要用在內存序列化上,經過Parcelable將對象序列化到存儲設備 中或者將對象序列化後經過網絡傳輸也都是能夠的,可是這個過程會稍顯複雜,所以在這兩種狀況下建議你們使用Serializable。

參考

爲何非靜態內部類裏不能夠有靜態屬性

談談對kotlin的理解

因人而異,請自行整理答案

String 轉換成 integer的方式及原理

Integer a = 2;
private void test() {
    String s1 = a.toString();  //方式一
    String s2 = Integer.toString(a);  //方式二
    String s3 = String.valueOf(a);  //方式三
}
複製代碼

方式一源碼:

public String toString() {
        return toString(value);
    }

    public static String toString(int i) {
        if (i == Integer.MIN_VALUE)
            return "-2147483648";
        int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
        char[] buf = new char[size];
        getChars(i, size, buf);
        return new String(buf, true);
    }
複製代碼

能夠看出方式一最終調用的是方式二

經過toString()方法,能夠把整數(包括0)轉化爲字符串,可是 Integer 若是是 null 的話,就會報空指針異常

方式三源碼:

public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
複製代碼

能夠看出 當 Integer 是null的時候,返回的String是 字符串 "null" 而不是 null

相關文章
相關標籤/搜索