Java 基礎 String 的詳解

寫在前面

String 算是 Java 源碼中先要學習的,今天就從源碼的角度來重新認識一下

1.存儲結(jié)構(gòu)

看主流的 JDK 版本 1.8 ,String 內(nèi)部實際存儲結(jié)構(gòu)為 char 數(shù)組外臂,源碼如下:

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

    /** Cache the hash code for the string */
    private int hash; // Default to 0
    //其他內(nèi)容......

2.常用方法

2.1.構(gòu)造方法

其中 StringBuffer 和 StringBuilder 為參數(shù)的構(gòu)造函數(shù)用的比較少,但也要知道

    /**
     * String 為參數(shù)的構(gòu)造方法
     * @param  original
     *        A {@code String}
     */
    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

    /**
     * char[] 為參數(shù)構(gòu)造方法
     * @param  value
     *         The initial value of the string
     */
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }
    
    /**
     * StringBuffer 為參數(shù)的構(gòu)造方法
     * @param  buffer
     *         A {@code StringBuffer}
     */
    public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }

    /**
     * StringBuilder 為參數(shù)的構(gòu)造方法
     * @param   builder
     *          A {@code StringBuilder}
     * @since  1.5
     */
    public String(StringBuilder builder) {
        this.value = Arrays.copyOf(builder.getValue(), builder.length());
    }

2.2.equals()

String 中 equals() 是比較兩個字符串的值是否相等,== 才是比較字符串的引用是否相等,equals() 重寫了父類 Object 方法锉屈,傳參也為 Object 類型,方法中會通過 instanceof 判斷垮耳,是 String 類型才進行下一步颈渊。

這里提一下遂黍,Object 父類中 equals() 和 == 對于引用類型的作用是一樣的。

    /**
    * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    public boolean equals(Object anObject) {
        if (this == anObject) {// 對象引用相同直接返回 true
            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])//轉(zhuǎn)化為字符數(shù)組,對比每個字符俊嗽,有一個不相同就是 fasle
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

有一個和 equels 相似的方法 equalsIgnoreCase(String)雾家,忽略大小寫對比,傳參為 String 類型

2.3.compareTo()

compareTo() 和 equels() 處理方式類似绍豁,都是字符對比芯咧,不同的是,equels() 比較兩字符串相同返回 true竹揍,不相同返回 false;compareTo() 比較兩字符串相同返回 0鬼佣,不相同返回 其他 int 類型數(shù)值驶拱。并且 compareTo() 只能接收 String 類型晶衷。

還有一個和 compareTo() 比較類似的方法 compareToIgnoreCase()阴孟,用于忽略大小寫后比較兩個字符串。

    /**
     * @param   anotherString   the {@code String} to be compared.
     * @return  the value {@code 0} if the argument string is equal to
     *          this string; a value less than {@code 0} if this string
     *          is lexicographically less than the string argument; and a
     *          value greater than {@code 0} if this string is
     *          lexicographically greater than the string argument.
     */
    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

2.4.其他重要方法

  • indexOf():查詢字符串首次出現(xiàn)的下標位置
  • lastIndexOf():查詢字符串最后出現(xiàn)的下標位置
  • contains():查詢字符串中是否包含另一個字符串
  • toLowerCase():把字符串全部轉(zhuǎn)換成小寫
  • toUpperCase():把字符串全部轉(zhuǎn)換成大寫
  • length():查詢字符串的長度
  • trim():去掉字符串首尾空格
  • replace():替換字符串中的某些字符
  • split():把字符串分割并返回字符串數(shù)組
  • join():把字符串數(shù)組轉(zhuǎn)為字符串

3.常遇問題

3.1.String 和 StringBuilder锹漱、StringBuffer

String 是不可變的,在字符串拼接的時候使用 String 會很耗性能慕嚷,因此有了 StringBuilder 和 StringBuffer,它們有 2 方法 append 和 insert 可以實現(xiàn)字符串拼接喝检,唯一不同的是 StringBuffer 使用 synchronized 來保證線程安全

//StringBuffer 截取片段,具體可以看 StringBuffer 類源碼

    @Override
    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }

    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
    //其他......


    /**
     * @throws StringIndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public synchronized StringBuffer insert(int offset, Object obj) {
        toStringCache = null;
        super.insert(offset, String.valueOf(obj));
        return this;
    }

    /**
     * @throws StringIndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public synchronized StringBuffer insert(int offset, String str) {
        toStringCache = null;
        super.insert(offset, str);
        return this;
    }
   //其他......
//StringBuilder截取片段挠说,具體可以看 StringBuilder類源碼

    @Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
    //其他......


    /**
     * @throws StringIndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public StringBuilder insert(int offset, Object obj) {
            super.insert(offset, obj);
            return this;
    }

    /**
     * @throws StringIndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public StringBuilder insert(int offset, String str) {
        super.insert(offset, str);
        return this;
    }
    //其他......

StringBuffer 保證線程安全,所以性能不是很高,JDK 1.5 就有了 StringBuilder

3.2.String 為什么用 final 修飾

使用 final 修飾的第一個好處是安全损俭;第二個好處是高效,例如

String s1 = "java";
String s2 = "java";

只有字符串是不可變時,我們才能實現(xiàn)字符串常量池杆兵,字符串常量池可以為我們緩存字符串,提高程序的運行效率琐脏,如下圖所示:


在這里插入圖片描述

3.3.JVM 中存儲

String 常用的 2 種創(chuàng)建方式,有 String a1 = "java" 和 String a2 = new Strring("java"),但他們在內(nèi)存中的存放方式不同,JDK1.8 中創(chuàng)建啊變量 a1祭衩,會先從常量池中找字符串 “java”,如果有直接返回灶体,如果沒有則先在常量池中創(chuàng)建該字符串再返回,而變量 a2會直接在堆內(nèi)存上創(chuàng)建掐暮,a2 調(diào)用方法 intern() 會把字符串保存到常量池蝎抽,例如

String a1 = "java";
String a2 = new Strring("java");
String a3 = "a2.intern();

System.out.println(a1 == a2); // false
System.out.println(a1 == a3); // true

JVM 存儲位置如圖


在這里插入圖片描述

PS:JDK 1.7 之后把永生代換成的元空間,把字符串常量池從方法區(qū)移到了 Java 堆上路克。

結(jié)束......

如果有哪些不對的地方煩請指認樟结,先行感謝

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市精算,隨后出現(xiàn)的幾起案子瓢宦,更是在濱河造成了極大的恐慌,老刑警劉巖灰羽,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驮履,死亡現(xiàn)場離奇詭異,居然都是意外死亡廉嚼,警方通過查閱死者的電腦和手機玫镐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怠噪,“玉大人恐似,你說我怎么就攤上這事“睿” “怎么了矫夷?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長憋槐。 經(jīng)常有香客問我双藕,道長,這世上最難降的妖魔是什么秦陋? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任蔓彩,我火速辦了婚禮,結(jié)果婚禮上驳概,老公的妹妹穿的比我還像新娘赤嚼。我一直安慰自己,他們只是感情好顺又,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布更卒。 她就那樣靜靜地躺著,像睡著了一般稚照。 火紅的嫁衣襯著肌膚如雪蹂空。 梳的紋絲不亂的頭發(fā)上俯萌,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音上枕,去河邊找鬼咐熙。 笑死,一個胖子當著我的面吹牛辨萍,可吹牛的內(nèi)容都是我干的棋恼。 我是一名探鬼主播锈玉,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼拉背,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了椅棺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤昼汗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蛙吏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡励烦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年泼诱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屉栓。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡友多,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出域滥,到底是詐尸還是另有隱情,我是刑警寧澤启绰,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布委可,位于F島的核電站,受9級特大地震影響撤缴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜微宝,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一虎眨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧岳守,春花似錦、人聲如沸湿痢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽臀规。三九已至,卻和暖如春塔嬉,著一層夾襖步出監(jiān)牢的瞬間租悄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工记盒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纪吮。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像碾盟,于是被迫代替她去往敵國和親棚辽。 傳聞我的和親對象是個殘疾皇子屈藐,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 四联逻、集合框架 1:String類:字符串(重點) (1)多個字符組成的一個序列,叫字符串包归。生活中很多數(shù)據(jù)的描述都采...
    佘大將軍閱讀 736評論 0 2
  • 《Java從小白到大畔梅》紙質(zhì)版已經(jīng)上架了!H泛瓤的! 由字符組成的一串字符序列,稱為“字符串”堤瘤,在前面的章節(jié)中也多次用到...
    tony關東升閱讀 803評論 0 2
  • java中String的常用方法 1本辐、length()字符串的長度 例:char chars[]={'a','b'...
    赤赤有名閱讀 2,036評論 0 10
  • 廣闊宇宙慎皱,壯麗銀河,茫茫九州茫多,億萬生民忽刽,微塵若我夺欲,煢煢獨立今膊,氣血之身,別無二致斑唬。唯我心經(jīng),獨一無二恕刘,心之內(nèi)外,更無...
    袁澤華閱讀 612評論 0 0
  • 總有一天坷澡, 我會成為一個沉默的人 獨自坐在塵封的往事 看遍春光献起、愛情、山河 只有時間隨時換上新鮮的衣裳 根本不能追...
    千里萬里心里夢里i閱讀 6,642評論 38 112