基礎(chǔ)知識

一、 String 和 StringBuffer、StringBuilder 的區(qū)別是什么?String 為什么是不可變的?

1. String
String
  • String 類中使用 final 關(guān)鍵字字符數(shù)組保存字符串, private final char value[],所以 String對象是不可變的。
  • 每次對 String 類型進行改變的時候,都會生成一個新的 String 對象,然后將指針指向新的 String 對象。原先的對象依舊在內(nèi)存中,但是指針不再指向它,那么這個對象就會成為垃圾內(nèi)存,在某一個特定的時刻有Java虛擬機回收。
  • String 中的對象是不可變的,也就可以理解為常量,線程安全。
2. StringBuffer
StringBuffer



擴容
  • StringBuilder 與 StringBuffer 都繼承自 AbstractStringBuilder 類,在AbstractStringBuilder中也是使用字符數(shù)組保存字符串 char[]value 但是沒有用 final 關(guān)鍵字修飾,所以這兩種對象都是可變的。
  • AbstractStringBuilder 是 StringBuilder 與StringBuffer 的公共父類,定義了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 對方法加了同步鎖或者對調(diào)用的方法加了同步鎖,所以是線程安全的。
  • StringBuffer 每次都會對 StringBuffer 對象本身進行操作,而不是生成新的對象并改變對象引用。相同情況下使用
  • StringBuffer()的初始容量可以容納16個字符,當該對象的實體存放的字符的長度大于16時,實體容量就自動增加。(嘗試將新容量擴為大小變成2倍+2 if 判斷一下 容量如果不夠,直接擴充到需要的容量大小。)
3. StringBuilder
  • 可變
  • StringBuilder 并沒有對方法進行加同步鎖,所以是非線程安全的。
  • StirngBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風險。

對于三者使用的總結(jié):

  1. 操作少量的數(shù)據(jù) = String
  2. 單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) = StringBuilder
  3. 多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) = StringBuffer

二、 String s = new String("abc");一共創(chuàng)建了幾個對象?

  1. 如果字符串常量池中不存在“abc”,該語句執(zhí)行時會先在字符串常量池中創(chuàng)建一個“abc”對象,在執(zhí)行new語句時在堆區(qū)開辟新的空間,創(chuàng)建“abc”字符串,同時棧區(qū)會有一個引用s指向堆區(qū)的對象,此時如果要算上棧區(qū)的引用,共創(chuàng)建3個對象,不算,則創(chuàng)建兩個對象。

  2. 如果字符串常量池中存在“abc”,則只會在堆區(qū)創(chuàng)建一個“abc”字符串,同時棧區(qū)有一個引用指向堆中的對像。如果算上棧中的引用,共創(chuàng)建了兩個對象,不算,則創(chuàng)建了一個對象。

三、 == 與 equals

  1. == : 它的作用是判斷兩個對象的地址是不是相等。即,判斷兩個對象是不是同一個對象。(基本數(shù)據(jù)類型==比較的是值,引用數(shù)據(jù)類型==比較的是內(nèi)存地址)
  2. equals() : 它的作用也是判斷兩個對象是否相等。但它一般有兩種使用情況:
    • 情況1:類沒有覆蓋 equals() 方法。則通過 equals() 比較該類的兩個對象時,等價于通過“==”比較這兩個對象。
    • 情況2:類覆蓋了 equals() 方法。一般,我們都覆蓋 equals() 方法來兩個對象的內(nèi)容相等;若它們的內(nèi)容相等,則返回 true (即,認為這兩個對象相等)。
舉個例子
public class test1 {
  public static void main(String[] args) {
    String a = new String("ab"); // a 為一個引用
    String b = new String("ab"); // b為另一個引用,對象的內(nèi)容一樣
    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 方法是比較的對象的內(nèi)存地址,而 String 的equals 方法比較的是對象的值。

  • 當創(chuàng)建 String 類型的對象時,虛擬機會在常量池中查找有沒有已經(jīng)存在的值和要創(chuàng)建的值相同的對象,如果有就把它賦給當前引用。如果沒有就在常量池中重新創(chuàng)建一個 String 對象。

四、關(guān)于 final 關(guān)鍵字的一些總結(jié)

final關(guān)鍵字主要用在三個地方:變量、方法、類。

  1. 對于一個final變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始化之后便不能更改;如果是引用類型的變量,則在對其初始化之后便不能再讓其指向另一個對象。

  2. 當用final修飾一個類時,表明這個類不能被繼承。final類中的所有成員方法都會被隱式地指定為final方法。

  3. 使用final方法的原因有兩個。第一個原因是把方法鎖定,以防任何繼承類修改它的含義;第二個原因是效率。在早期的Java實現(xiàn)版本中,會將final方法轉(zhuǎn)為內(nèi)嵌調(diào)用。但是如果方法過于龐大,可能看不到內(nèi)嵌調(diào)用帶來的任何性能提升(現(xiàn)在的Java版本已經(jīng)不需要使用final方法進行這些優(yōu)化了)。類中所有的private方法都隱式地指定為fianl。

五、Object類的常見方法總結(jié)

Object類是一個特殊的類,是所有類的父類。它主要提供了以下11個方法


Object
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容