String面試知識點總結

String三大核心機制

  1. 不變性:是一個immutable模式的對象,不變模式的主要作用是當一個對象需要被多線程共享並頻繁訪問時,可以保證數據的一致性
  2. 常量池優化:String對象創建後,會在字符串常量池進行緩存,下次創建同樣的對象時,會直接返回緩存的引用
  3. final:String類不可繼承,提高了系統的安全性

常見的考點

String類型不是基本數據類型,String底層實現爲char類型的數組

// 部分源碼
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

String實例化有兩種方式:

  • 直接賦值
  • 通過構造函數:可以以字符串的形式傳入,也可以傳入一個char類型的數組
public static void main(String[] args) {
    char[] arr = {'你', '好'};
    String str1 = new String(arr);
    String str2 = new String("Hello World");
    String str3 = "Hello World";
}

直接賦值和通過構造函數創建的主要區別在於儲存的區域不同,直接賦值的儲存在字符串常量池中

public static void main(String[] args) {
    String str1 = "Hello";
    String str2 = "Hello";
    System.out.println(str1 == str2); // true
}

通過構造函數創建的儲存在堆內存中

public static void main(String[] args) {
    String str1 = new String("Hello");
    String str2 = new String("Hello");
    System.out.println(str1 == str2); // false
}

String的equals方法:String的equals方法重寫了Object類equals的方法,將String類型轉換爲char類型的數組,然後依次比較數組的每一位。

// equals源碼
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不可變性:String的值一旦修改就會是一個新的對象,不是再原來的對象了

public static void main(String[] args) {
    String str1 = "abc";
    String str2 = str1;
    str1 += "def";
    System.out.println(str1 == str2); // false
}

String的intern()方法

當調用某個字符串對象的intern()方法時,會先去字符串常量池中尋找,如果已經存在一個值相等的字符串對象的話,則直接返回該對象的引用;如果不存在,則在字符串常量池中創建該對象,並返回。

public static void main(String[] args) {
    String str1 = "Hello World";
    String str2 = new String("Hello World");
    System.out.println(str1 == str2); // false
    String str3 = str2.intern();
    System.out.println(str1 == str3); // true
}

String 常用方法

1、字符串截取

  • public String substring(int beginIndex):從beginIndex開始截取,直到字符串結尾
  • public String substring(int beginIndex,int endIndex):從beginIndex開始截取,直到endIndex結束,不包含endIndex

注意:截取之後原字符串不變

public static void main(String[] args) {
    String str1 = "HelloWorld";
    String substr1 = str1.substring(4);
    String substr2 = str1.substring(4, 7);
    System.out.println(str1);    // HelloWorld
    System.out.println(substr1); // oWorld
    System.out.println(substr2); // oWo
}

2、字符串分割

  • public String[] split(String regex):將字符串按照regex分割成數組,同時支持正則表達式
public static void main(String[] args) {
    String str = "python java;golang,javascript";
    String[] arr = str.split("[,|;| ]");
    System.out.println(Arrays.toString(arr)); // [python, java, golang, javascript]
}

面試真題

要弄懂String類型,要先明白常量和變量的區別。常量是在編譯時期就知道值是多少的;而變量是在運行時期才能確定值的

public static void main(String[] args) {
    String str1 = "helloWorld";
    String str2 = "hello" + "World";
    System.out.println(str1 == str2); // true
}

字符串hello和字符串World都是常量,拼接之後的值還是保存在字符串常量池中的,所以地址相同

public static void main(String[] args) {
    String str1 = "helloWorld";
    String str2 = "hello";
    str2 += "World";
    System.out.println(str1 == str2); // false
}

看似和上一題差不多,但實際上上一題的str2是有兩個常量相加得到的,所以str2儲存的是常量池中地址;而這一道題的str2是一個變量,變量儲存在堆之中,同樣一個變量加一個常量還是儲存在堆中的,所以地址是不同的

public static void main(String[] args) {
    String str1 = "helloWorld";
    String str2 = "hello";
    String str3 = str2 + "World";
    System.out.println(str1 == str3); // false
}

同理,str1在常量池中,str3在堆中,所以他們的引用一定不相等

public static void main(String[] args) {
    String str1 = "helloWorld";
    final String str2 = "hello";
    String str3 = str2 + "World";
    System.out.println(str1 == str3); // true
}

這裏str2加上final關鍵字之後稱爲常量,保存在常量池中,在加上常量World之後返回的值還是常量,所以str1str3是相等的

public static void main(String[] args) {
    String str1 = "helloWorld";
    final String str2 = new String("hello");
    String str3 = str2 + "World";
    System.out.println(str1 == str3); // false
}

這裏雖然加上了final但是通過構造函數創建的對象本身就是儲存在堆中的

public static void main(String[] args) {
    String str1 = "helloWorld";
    String str2 = "hello";
    String str3 = "World";
    String str4 = str2 + str3;
    System.out.println(str1 == str4); // false
    System.out.println(str1 == str4.intern()); // true
}

參考資料:https://blog.csdn.net/qq_34490018/article/details/82110578

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