備戰「金九銀十」10道String高頻面試題解析

前言

String 是咱們實際開發中使用頻率很是高的類,Java 能夠經過 String 類來建立和操做字符串,使用頻率越高的類,咱們就越容易忽視它,由於見的多因此熟悉,由於熟悉因此認爲它很簡單,其實只是瞭解到皮毛,並無真正掌握,而 String 又是面試的高頻考點,因此咱們有必要將 String 這個類深刻研究,完全搞定,本節課就爲你們詳細講解 String 的核心機制以及實際使用。

String 三大核心:程序員

一、不變性:String 是隻讀字符串,是一個典型的 immutable 對象,對它進行任何操做,其實都是建立一個新的對象,再把引用指向該對象。不變模式的主要做用在於當一個對象須要被多線程共享並頻繁訪問時,能夠保證數據的一致性。
二、常量池優化:String 對象建立以後,會在字符串常量池中進行緩存,若是下次建立一樣的對象時,會直接返回緩存的引用。
三、final:使用 final 來定義 String 類,表示 String 類不能被繼承,提升了系統的安全性。

String 不是基本數據類型

這是很基礎的東西,可是不少初學者卻容易忽視,Java 的 8 種基本數據類型中不包括 String,基本數據類型中用來描述文本數據的是 char,可是它只能表示單個字符,好比 'a','好' 之類的,若是要描述一段文本,就須要用多個 char 類型的變量,也就是一個 char 類型數組,好比「你好」 就是長度爲2的數組 char[] chars = {'你','好'};
可是使用數組過於麻煩,因此就有了 String,String 底層就是一個 char 類型的數組,只是使用的時候開發者不須要直接操做底層數組,用更加簡便的方式便可完成對字符串的使用。

高頻面試題解析

一、== 和 equals 的區別?
== 能夠理解爲是比較棧內存中的值,若是變量是基本數據類型,則棧內存中存放的就是具體數值,若是是引用類型,則棧中存放的是引用的內存地址。
因此對於基本數據類型,== 是比較值是否相等,對於引用數據類型,比較的是引用的內存地址是否相等。
equals 是 Object 類提供的一個方法,其本質就是在用 == 進行判斷。
public boolean equals(Object obj) {
  return (this == obj);
}

複製代碼
同時 Java 中任意一個類均可以對其進行重寫,根據具體需求從新定義其判斷邏輯,好比咱們自定義一個 Student 類,以下所示。
public class Student {
    private Integer id;
    private String name;
    public Student(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

複製代碼
建立兩個成員變量值徹底相等的實例化對象,並用 equals 方法判斷是否相等。
Student student1 = new Student(1,"張三");
Student student2 = new Student(1,"張三");
System.out.println(student1.equals(student2));

複製代碼
結果爲 false,由於有兩個實例化對象,就必然會在堆內存中開闢兩塊空間來存儲,引用必定是不相同的。而在現實的邏輯中,若是兩個學生的 id 和 name 都同樣,咱們就認爲他們是同一個學生,用程序如何來實現呢?經過重寫 equals 方法便可,以下所示。
public class Student {
    private Integer id;
    private String name;
    public Student(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
    @Override
    public boolean equals(Object obj) {
        Student student = (Student) obj;
        if(id.equals(student.id) && name.equals(student.name)){
            return true;
        }
        return false;
    }
}

複製代碼
再次運行代碼,返回值爲 true。
二、下面代碼的運行結果是?
String str1 = "Hello World";
String str2 = "Hello"+" World";
System.out.println(str1 == str2);

複製代碼
true,"Hello" 和 " World" 都是字符串字面值,字符串字面值 + 字符串字面值的結果仍然保存在字符串常量池中,因此 str1 和 str2 相同。
三、下面代碼的運行結果是?
String str1 = "Hello World";
String str2 = "Hello";
str2 += " World";
System.out.println(str1 == str2);

複製代碼
false,這題看似與第 2 題同樣,爲何結果徹底不一樣呢?由於 str2 = "Hello"+" World" 是直接建立,str2 = "Hello"; str2 = "Hello"; 是先建立再修改,同時修改完成以後的字符串是放在堆內存中的,爲何呢?由於 str2 是一個字符串變量," World" 是字符串字面值,當字符串字面值與 String 類型變量拼接時,獲得的新字符串再也不保存在常量池中,而是在堆中開闢一塊新的空間來存儲,因此 str1 引用指向字符串常量池,str2 引用指向堆內存,確定不相同。
四、下面代碼的運行結果是?
String str1 = "Hello World";
String str2 = " World";
String str3 = "Hello"+str2;
System.out.println(str1 == str3);

複製代碼
false,str2 是變量,"Hello" 是字符串字面值,字符串字面值 + 變量會在堆內存中開闢新的空間來存儲,因此 str1 和 str3 不一樣。
五、下面代碼的運行結果是?
String str1 = "Hello World";
final String str2 = " World";
String str3 = "Hello"+str2;
System.out.println(str1 == str3);

複製代碼
true,"Hello" 是字符串字面值,str2 是常量,字符串字面值+常量的結果仍然保存在字符串常量池中,因此 str1 和 str3 相同。
六、下面代碼的運行結果是?
String str1 = "Hello World";
final String str2 = new String(" World");
String str3 = "Hello"+str2;
System.out.println(str1 == str3);

複製代碼
false,str2 是常量,可是 new String(" World") 保存在堆內存中,因此即便使用 final 進行了修飾,str2 仍然保存在堆中,則 str3 也就保存在堆中,因此 str1 和 str3 不一樣。
七、下面代碼的運行結果是?
String str1 = "Hello World";
String str2 = "Hello";
String str3 = " World";
String str4 = str2 + str3;
System.out.println(str4.intern() == str1);

複製代碼
true,當調用 str4 的 intern 方法時,若是字符串常量池已經包含一個等於 str4 的字符串,則返回該字符串,不然將 str4 添加到字符串常量池中,並返回其引用,因此 str4.intern() 與 str1 相同。
八、什麼是字符串常量池?
字符串常量池位於堆內存中,專門用來存儲字符串常量,能夠提升內存的使用率,避免開闢多塊空間存儲相同的字符串,在建立字符串時 JVM 會首先檢查字符串常量池,若是該字符串已經存在池中,則返回它的引用,若是不存在,則實例化一個字符串放到池中,並返回其引用。
九、String 是線程安全的嗎?
String 是不可變類,一旦建立了String對象,咱們就沒法改變它的值。所以它是線程安全的,同一個字符串實例能夠被多個線程共享,保證了多線程的安全性。
十、在使用 HashMap 的時候,用 String 作 key 有什麼好處?
HashMap 內部實現是經過 key 的 hashcode 來肯定 value 的存儲位置,由於字符串是不可變的,因此當建立字符串時,它的 hashcode 被緩存下來,不須要再次計算,因此相比於其餘對象更快。

最後

歡迎你們關注個人公衆號【程序員追風】,文章都會在裏面更新,整理的資料也會放在裏面。面試

相關文章
相關標籤/搜索