天天看點

字元串常量池與StringBuilder

文章目錄

一、字元串常量池

public static void main(String[] args) {
 
        String s1 = "abc";
        String s2 = "abc";
        String s3 = new String("abc");
        String s4 = new String("abc");
        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
        System.out.println(s3 == s4);
    }           

上面兩種建立String對象的方式相同嗎?

字元串常量池與StringBuilder

在Java程式中,“ ”雙引号引起來的字面類型的常量經常頻繁使用,為了使程式的運作速度更快、更節省記憶體,Java為8種基本資料類型和String類都提供了常量池。

1.使用字元常量直接指派:

public static void main(String[] args) {
 
        String s1 = "abc";
        String s2 = "abc";
        System.out.println(s1 == s2);
  }           
字元串常量池與StringBuilder

在直接用字面常量指派String時,先在常量池裡找,是否有這個字元串,如果沒有則建立,我們發現常量池并沒有abc,是以我們建立一個“abc”。

字元串常量池與StringBuilder

當第二次建立"abc"字元串賦給s2時直接指向就行.

字元串常量池與StringBuilder

s1和s2指向的是同一塊引用,是以s1 == s2。

2.通過new建立String類對象:

字元串常量池與StringBuilder

隻要new對象,它的引用就是唯一的.

使用常量串建立String類型對象的效率更高,而且更節省空間。

3.intern方法:

intern 是一個native方法(Native方法指:底層使用C++實作的,看不到其實作的源代碼),該方法的作用是手動将建立的String對象添加到常量池中。

public static void main(String[] args) {
 
        char[] ch = new char[]{
 'a','b','c'};
        String s1 = new String(ch);
        String s2 = "abc";
        System.out.println(s1 == s2);
    }           
字元串常量池與StringBuilder

我們可見s1 和 s2指向不同的引用

public static void main(String[] args) {
 
        char[] ch = new char[]{
 'a','b','c'};
        String s1 = new String(ch);
        s1.intern();
        String s2 = "abc";
        System.out.println(s1 == s2);
    }           

intern()方法是将s1中的引用放入常量池中.當s2建立時,就會指向常量池的那個引用.

字元串常量池與StringBuilder

二、字元串的不可變性

String是一種不可變對象. 字元串中的内容是不可改變。

String的源碼中,注解中寫到String是一個常量,不可修改.

字元串常量池與StringBuilder

我們在來看String類型是如何存儲字元串的

字元串常量池與StringBuilder

可能有人說因為被final修飾,是以不能修改,首先這是一個很大的誤區,final修飾隻能說明value引用的對象不能修改,而不是說value引用的值不能修改.

字元串常量池與StringBuilder

我們随便打開一個String的方法,這裡打開的是toUpperCase方法,可以發現:所有涉及到修改字元串内容的方法都是建立一個新對象傳回.

String為什麼要設計成不可變的?

  1. 友善實作字元串對象池. 如果 String 可變, 那麼對象池就需要考慮寫時拷貝的問題了.
  2. 不可變對象是線程安全的.
  3. 不可變對象更友善緩存 hash code, 作為 key 時可以更高效地儲存到 HashMap 中.

三、字元串修改

字元串是不能修改的,每次修改都會建立新對象,效率非常低下.

public static void main(String[] args) {
 
        String str = "wo"+"yao"+"jin"+"da"+"chang";
        System.out.println(str);
    }           
字元串常量池與StringBuilder

當然是可以正常輸出的,我們看一下彙編.

字元串常量池與StringBuilder

我們會發現建立了許多StringBuilder對象,去拼接字元串,這樣效率十分低下。

public static void main(String[] args) {
 
        long start = System.currentTimeMillis();
        String s = "";
        for(int i = 0; i < 10000; ++i){
 
            s += i;
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
        start = System.currentTimeMillis();
        StringBuffer sbf = new StringBuffer("");
        for(int i = 0; i < 10000; ++i){
 
            sbf.append(i);
        }
        end = System.currentTimeMillis();
        System.out.println(end - start);
        start = System.currentTimeMillis();
        StringBuilder sbd = new StringBuilder();
        for(int i = 0; i < 10000; ++i){
 
            sbd.append(i);
        }
        end = System.currentTimeMillis();

        System.out.println(end - start);
    }           
字元串常量池與StringBuilder

我們發現在對String進行修改時,String與StringBuffer和StringBuilder相差幾百倍.

四、StringBuilder與StringBuffer的方法

字元串常量池與StringBuilder

這裡都是StringBuffer和StringBuilder的一些方法.

1.append

拼接字元串

public static void main(String[] args) {
 
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("wo yao jin da chang!");
        System.out.println(stringBuilder);
    }           
字元串常量池與StringBuilder

2.reverse

字元串逆置

public static void main(String[] args) {
 
        StringBuilder stringBuilder = new StringBuilder("abcd");
        stringBuilder.reverse();
        System.out.println(stringBuilder);
    }           
字元串常量池與StringBuilder

3.delete

删除指定範圍内的字元

public static void main(String[] args) {
 
        StringBuilder stringBuilder = new StringBuilder("abcd");
        stringBuilder.delete(0,2);
        System.out.println(stringBuilder);
    }           
字元串常量池與StringBuilder

String與StringBuilder互相轉換:

String和StringBuilder最大的差別在于String的内容無法修改,而StringBuilder的内容可

以修改。頻繁修改字元串的情況考慮使用StringBuilder

1.String變為StringBuilder

public static void main(String[] args) {
 
        //調用StringBuilder構造方法
        String str = "abc";
        StringBuilder stringBuilder = new StringBuilder(str);
    }           
public static void main(String[] args) {
 
        //append拼接字元串
        String str = "abc";
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(str);
        System.out.println(stringBuilder);
    }           
字元串常量池與StringBuilder

1.StringBuilder變為String

字元串常量池與StringBuilder

我們可以看一下StringBuilder的toString()方法傳回的是一個String對象.

public static void main(String[] args) {
 
        //StringBuilder的toString()方法
        StringBuilder stringBuilder = new StringBuilder("abc");
        String str = stringBuilder.toString();
        System.out.println(str);
    }           
字元串常量池與StringBuilder

四、StringBuilder與StringBuffer差別

String、StringBuffer、StringBuilder的差別:

1.String的内容不可修改,StringBuffer與StringBuilder的内容可以修改.

2.StringBuffer與StringBuilder大部分功能是相似的

3.StringBuffer采用同步處理,屬于線程安全操作;而StringBuilder未采用同步處理,屬于線程不安全操作

字元串常量池與StringBuilder

StringBuffer中的每個方法加入了synchronized,它就相當于是一把鎖,隻要有第一個人通路這個方法,那麼這個方法就隻能等第一個人通路完成之後,剩下的人才能通路.

String str = new String("abc"); 
String str = new String("ab") + new String("c");           

繼續閱讀