在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Java/ 字符串
Java 集合細(xì)節(jié)(四):保持 compareTo 和 equals 同步
Iterator
使用序列化實(shí)現(xiàn)對(duì)象的拷貝
fail-fast 機(jī)制
關(guān)鍵字 final
Vector
HashTable
Java 集合細(xì)節(jié)(一):請(qǐng)為集合指定初始容量
強(qiáng)制類型轉(zhuǎn)換
數(shù)組之一:認(rèn)識(shí) JAVA 數(shù)組
Java 集合細(xì)節(jié)(三):subList 的缺陷
hashCode
ArrayList
數(shù)組之二
List 總結(jié)
LinkedList
Java 提高篇(九)—–實(shí)現(xiàn)多重繼承
Java 的四舍五入
關(guān)鍵字 static
理解 Java 的三大特性之多態(tài)
抽象類與接口
集合大家族
異常(二)
Java 集合細(xì)節(jié)(二):asList 的缺陷
Map 總結(jié)
TreeSet
equals() 方法總結(jié)
Java 提高篇(十)—–詳解匿名內(nèi)部類
HashMap
Stack
詳解內(nèi)部類
TreeMap
異常(一)
詳解 Java 定時(shí)任務(wù)
HashSet
字符串
理解 Java 的三大特性之繼承
理解 Java 的三大特性之封裝
代碼塊

字符串

可以證明,字符串操作是計(jì)算機(jī)程序設(shè)計(jì)中最常見的行為。

一、String

首先我們要明確,String 并不是基本數(shù)據(jù)類型,而是一個(gè)對(duì)象,并且是不可變的對(duì)象。查看源碼就會(huì)發(fā)現(xiàn) String 類為 final 型的(當(dāng)然也不可被繼承),而且通過查看 JDK 文檔會(huì)發(fā)現(xiàn)幾乎每一個(gè)修改 String 對(duì)象的操作,實(shí)際上都是創(chuàng)建了一個(gè)全新的 String 對(duì)象。

字符串為對(duì)象,那么在初始化之前,它的值為 null,到這里就有必要提下 ””、null、new String() 三者的區(qū)別。null 表示 string 還沒有 new ,也就是說對(duì)象的引用還沒有創(chuàng)建,也沒有分配內(nèi)存空間給他,而””、new String() 則說明了已經(jīng) new 了,只不過內(nèi)部為空,但是它創(chuàng)建了對(duì)象的引用,是需要分配內(nèi)存空間的。打個(gè)比方:一個(gè)空玻璃杯,你不能說它里面什么都沒有,因?yàn)槔锩嬗锌諝猓?dāng)然也可以把它弄成真空,null與” “、new String() 的區(qū)別就象真空與空氣一樣。

在字符串中存在一個(gè)非常特殊的地方,那就是字符串池。每當(dāng)我們創(chuàng)建一個(gè)字符串對(duì)象時(shí),首先就會(huì)檢查字符串池中是否存在面值相等的字符串,如果有,則不再創(chuàng)建,直接放回字符串池中對(duì)該對(duì)象的引用,若沒有則創(chuàng)建然后放入到字符串池中并且返回新建對(duì)象的引用。這個(gè)機(jī)制是非常有用的,因?yàn)榭梢蕴岣咝剩瑴p少了內(nèi)存空間的占用。所以在使用字符串的過程中,推薦使用直接賦值(即String s=”aa”),除非有必要才會(huì)新建一個(gè) String 對(duì)象(即String s = new String(”aa”))。

對(duì)于字符串的使用無非就是這幾個(gè)方面:

1、字符串比較

equals() ——判斷內(nèi)容是否相同。

compareTo() ——判斷字符串的大小關(guān)系。

compareToIgnoreCase(String int) ——在比較時(shí)忽略字母大小寫。

== ——判斷內(nèi)容與地址是否相同。

equalsIgnoreCase() ——忽略大小寫的情況下判斷內(nèi)容是否相同。

reagionMatches() ——對(duì)字符串中的部分內(nèi)容是否相同進(jìn)行比較(詳情請(qǐng)參考API)。

2、字符串查找

charAt(int index) ——返回指定索引 index 位置上的字符,索引范圍從 0 開始。

indexOf(String str)——從字符串開始檢索str,并返回第一次出現(xiàn)的位置,未出現(xiàn)返回 -1。

indexOf(String str,int fromIndex);——從字符串的第 fromIndex 個(gè)字符開始檢索 str。

lastIndexOf(String str)——查找最后一次出現(xiàn)的位置。

lastIndexOf(String str,int fromIndex)—-從字符串的第fromIndex個(gè)字符查找最后一次出現(xiàn)的位置。

starWith(String prefix,int toffset)—–測(cè)試此字符串從指定索引開始的子字符串是否以指定前綴開始。

starWith(String prefix)——測(cè)試此字符串是否以指定的前綴開始。

endsWith(String suffix)——測(cè)試此字符串是否以指定的后綴結(jié)束。

3、字符串截取

public String subString(int beginIndex)——返回一個(gè)新的字符串,它是此字符串的一個(gè)子字符串。

public String subString(int beginIndex,int endIndex)——返回的字符串是從 beginIndex 開始到 endIndex-1 的串。

4、字符串替換

public String replace(char oldChar,char newChar)。

public String replace(CharSequence target,CharSequence replacement)——把原來的 etarget 子序列替換為 replacement 序列,返回新串。

public String replaceAll(String regex,String replacement)——用正則表達(dá)式實(shí)現(xiàn)對(duì)字符串的匹配。注意 replaceAll 第一個(gè)參數(shù)為正則表達(dá)式,鄙人曾經(jīng)深受其害。

5、更多方法請(qǐng)參考 API

二、StringBuffer

StringBuffer 和 String 一樣都是用來存儲(chǔ)字符串的,只不過由于他們內(nèi)部的實(shí)現(xiàn)方式不同,導(dǎo)致他們所使用的范圍不同,對(duì)于 StringBuffer 而言,他在處理字符串時(shí),若是對(duì)其進(jìn)行修改操作,它并不會(huì)產(chǎn)生一個(gè)新的字符串對(duì)象,所以說在內(nèi)存使用方面它是優(yōu)于 String 的。

其實(shí)在使用方法,StringBuffer 的許多方法和 String 類都差不多,所表示的功能幾乎一模一樣,只不過在修改時(shí) StringBuffer 都是修改自身,而 String 類則是產(chǎn)生一個(gè)新的對(duì)象,這是他們之間最大的區(qū)別。

同時(shí) StringBuffer 是不能使用=進(jìn)行初始化的,它必須要產(chǎn)生 StringBuffer 實(shí)例,也就是說你必須通過它的構(gòu)造方法進(jìn)行初始化。

在 StringBuffer 的使用方面,它更加側(cè)重于對(duì)字符串的變化,例如追加、修改、刪除,相對(duì)應(yīng)的方法:

1、append():追加指定內(nèi)容到當(dāng)前 StringBuffer 對(duì)象的末尾,類似于字符串的連接,這里 StringBuffer 對(duì)象的內(nèi)容會(huì)發(fā)生改變。

2、insert:該類方法主要是在 StringBuffer 對(duì)象中插入內(nèi)容。

3、delete:該類方法主要用于移除 StringBuffer 對(duì)象中的內(nèi)容。

三、StringBuilder

StringBuilder 也是一個(gè)可變的字符串對(duì)象,他與 StringBuffer 不同之處就在于它是線程不安全的,基于這點(diǎn),它的速度一般都比 StringBuffer 快。與 StringBuffer 一樣,StringBuider 的主要操作也是 append 與 insert 方法。這兩個(gè)方法都能有效地將給定的數(shù)據(jù)轉(zhuǎn)換成字符串,然后將該字符串的字符添加或插入到字符串生成器中。

上面只是簡單的介紹了 String、StringBuffer、StringBuilder,其實(shí)對(duì)于這三者我們應(yīng)該更加側(cè)重于他們只見到的區(qū)別,只有理清楚他們之間的區(qū)別才能夠更好的使用他們。

四、正確使用 String、StringBuffer、StringBuilder

我們先看如下表格:

這里對(duì)于 String 是否為線程安全,鄙人也不是很清楚,原因:String 不可變,所有的操作都是不可能改變其值的,是否存在線程安全一說還真不好說?但是如果硬要說線程是否安全的話,因?yàn)閮?nèi)容不可變,永遠(yuǎn)都是安全的。

在使用方面由于 String 每次修改都需要產(chǎn)生一個(gè)新的對(duì)象,所以對(duì)于經(jīng)常需要改變內(nèi)容的字符串最好選擇 StringBuffer 或者 StringBuilder.而對(duì)于 StringBuffer,每次操作都是對(duì) StringBuffer 對(duì)象本身,它不會(huì)生成新的對(duì)象,所以 StringBuffer 特別適用于字符串內(nèi)容經(jīng)常改變的情況下。

但是并不是所有的 String 字符串操作都會(huì)比 StringBuffer 慢,在某些特殊的情況下,String 字符串的拼接會(huì)被 JVM 解析成 StringBuilder 對(duì)象拼接,在這種情況下 String 的速度比 StringBuffer 的速度快。如:

String name = ”I ” + ”am ” + ”chenssy ” ;

StringBuffer name = new StringBuffer(”I ”).append(” am ”).append(” chenssy ”);

對(duì)于這兩種方式,你會(huì)發(fā)現(xiàn)第一種比第二種快太多了,在這里 StringBuffer 的優(yōu)勢(shì)蕩然無存。其真實(shí)的原因就在于JVM做了一下優(yōu)化處理,其實(shí) String name = ”I ” + ”am ” + ”chenssy ” ;在 JVM 眼中就是 String name = ”I am chenssy ” ;這樣的方式對(duì)于 JVM 而言,真的是不要什么時(shí)間。但是如果我們?cè)谶@個(gè)其中增加一個(gè) String 對(duì)象,那么 JVM 就會(huì)按照原來那種規(guī)范來構(gòu)建 String 對(duì)象了。

對(duì)于這三者使用的場(chǎng)景做如下概括(參考:《編寫搞質(zhì)量代碼:改善 Java 程序的 151 個(gè)建議》):

1、String:在字符串不經(jīng)常變化的場(chǎng)景中可以使用 String 類,如:常量的聲明、少量的變量運(yùn)算等。

2、StringBuffer:在頻繁進(jìn)行字符串的運(yùn)算(拼接、替換、刪除等),并且運(yùn)行在多線程的環(huán)境中,則可以考慮使用 StringBuffer,例如 XML 解析、 HTTP 參數(shù)解析和封裝等。

3、StringBuilder:在頻繁進(jìn)行字符串的運(yùn)算(拼接、替換、刪除等),并且運(yùn)行在多線程的環(huán)境中,則可以考慮使用 StringBuffer,如 SQL 語句的拼裝、JSON 封裝等(貌似這兩個(gè)我也是使用|StringBuffer)。

更多有關(guān)于他們之間區(qū)別,請(qǐng)參考:http://www.cnblogs.com/zuoxiaolong/p/lang1.html 。鄙人就不畫蛇添足了。

五、字符串拼接方式

對(duì)于字符串而言我們經(jīng)常是要對(duì)其進(jìn)行拼裝處理的,在 Java 中提高了三種拼裝的方法:+、concat() 以及 append() 方法。這三者之間存在什么區(qū)別呢?先看如下示例:


    public class StringTest {

        /**
         * @desc 使用+、concat()、append()方法循環(huán)10W次
         * @author chenssy
         * @data 2013-11-16
         * @param args
         * @return void
         */
        public static void main(String[] args) {
            //+
            long start_01 = System.currentTimeMillis();
            String a = "a";
            for(int i = 0 ; i < 100000 ; i++){
                a += "b";
            }
            long end_01 = System.currentTimeMillis();
            System.out.println("  +   所消耗的時(shí)間:" + (end_01 - start_01) + "毫米");

            //concat()
            long start_02 = System.currentTimeMillis();
            String c = "c";
            for(int i = 0 ; i < 100000 ; i++){
                c = c.concat("d");
            }
            long end_02 = System.currentTimeMillis();
            System.out.println("concat所消耗的時(shí)間:" + (end_02 - start_02) + "毫米");

            //append
            long start_03 = System.currentTimeMillis();
            StringBuffer e = new StringBuffer("e");
            for(int i = 0 ; i < 100000 ; i++){
                e.append("d");
            }
            long end_03 = System.currentTimeMillis();
            System.out.println("append所消耗的時(shí)間:" + (end_03 - start_03) + "毫米");
        }
    }

    ------------
    Output:
     +   所消耗的時(shí)間:19080毫米
    concat所消耗的時(shí)間:9089毫米
    append所消耗的時(shí)間:10毫米

從上面的運(yùn)行結(jié)果可以看出,append()速度最快,concat()次之,+最慢。原因請(qǐng)看下面分解:

(一)+方式拼接字符串

在前面我們知道編譯器對(duì)+進(jìn)行了優(yōu)化,它是使用 StringBuilder 的 append() 方法來進(jìn)行處理的,我們知道 StringBuilder 的速度比 StringBuffer 的速度更加快,但是為何運(yùn)行速度還是那樣呢?主要是因?yàn)榫幾g器使用 append() 方法追加后要同 toString() 轉(zhuǎn)換成 String 字符串,也就說 str +=”b”等同于

str = new StringBuilder(str).append(“b”).toString();

它變慢的關(guān)鍵原因就在于 new StringBuilder() 和 toString(),這里可是創(chuàng)建了 10 W 個(gè) StringBuilder 對(duì)象,而且每次還需要將其轉(zhuǎn)換成 String,速度能不慢么?

(二)concat() 方法拼接字符串


    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        char buf[] = new char[count + otherLen];
        getChars(0, count, buf, 0);
        str.getChars(0, otherLen, buf, count);
        return new String(0, count + otherLen, buf);
        }

這是 concat() 的源碼,它看上去就是一個(gè)數(shù)字拷貝形式,我們知道數(shù)組的處理速度是非常快的,但是由于該方法最后是這樣的:return new String(0, count + otherLen, buf);這同樣也創(chuàng)建了 10 W 個(gè)字符串對(duì)象,這是它變慢的根本原因。

(三)append() 方法拼接字符串


    public synchronized StringBuffer append(String str) {
        super.append(str);
            return this;
        }

StringBuffer 的 append() 方法是直接使用父類 AbstractStringBuilder 的 append() 方法,該方法的源碼如下:


    public AbstractStringBuilder append(String str) {
        if (str == null) str = "null";
            int len = str.length();
        if (len == 0) return this;
        int newCount = count + len;
        if (newCount > value.length)
            expandCapacity(newCount);
        str.getChars(0, len, value, count);
        count = newCount;
        return this;
       }

與 concat() 方法相似,它也是進(jìn)行字符數(shù)組處理的,加長,然后拷貝,但是請(qǐng)注意它最后是返回并沒有返回一個(gè)新串,而是返回本身,也就說這這個(gè) 10 W 次的循環(huán)過程中,它并沒有產(chǎn)生新的字符串對(duì)象。

通過上面的分析,我們需要在合適的場(chǎng)所選擇合適的字符串拼接方式,但是并不一定就要選擇 append() 和 concat() 方法,原因在于+根據(jù)符合我們的編程習(xí)慣,只有到了使用 append() 和 concat() 方法確實(shí)是可以對(duì)我們系統(tǒng)的效率起到比較大的幫助,才會(huì)考慮,同時(shí)鄙人也真的沒有怎么用過 concat() 方法。

鞏固基礎(chǔ),提高技術(shù),不懼困難,攀登高峰?。。。。。?/code>