String詳解

来源:http://www.cnblogs.com/herbert2016/archive/2016/11/20/6083564.html
-Advertisement-
Play Games

在開發中,我們都會頻繁的使用String類,掌握String的實現和常用方法是必不可少的,當然,我們還需要瞭解它的內部實現。 一. String的實現 在Java中,採用了一個char數組實現String類型,這個char數組被定義為final類型,這就意味著一旦一個String被創建,那麼它就是不 ...


在開發中,我們都會頻繁的使用String類,掌握String的實現和常用方法是必不可少的,當然,我們還需要瞭解它的內部實現。

一. String的實現

在Java中,採用了一個char數組實現String類型,這個char數組被定義為final類型,這就意味著一旦一個String被創建,那麼它就是不可變的。除此之外,還定義了一個int類型的hash,用來保存該String的hash值。

 /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

二. String中的構造器

創建String的方法很多,構造器也有多個。但是其目的就是給value數組賦值。構造器中傳入的參數大致可以分為幾個部分:

src:來源,就是希望在value中保存的字元串,傳入的值可以是String,char數組,int數組,byte數組,Stringbuffer,StringBuilder,boolean值。

offset:src中字元串的起始位置。

count:src中賦值到value中的字元串的個數。

Charset:指定字元集。

當然,不是每一個構造器都需要這些參數,我們也不需要一個個都詳細掌握,只要知道大概存在哪些構造方法即可,要用的時候可以查詢API。

三. String中常用的方法以及實現

1. 獲取字元數組

獲取字元數組方法:

     public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)

該方法將String中指定位置的字元複製個dst,具體的實現如下:

 public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
    //對指定位置進行判斷
if (srcBegin < 0) { throw new StringIndexOutOfBoundsException(srcBegin); } if (srcEnd > value.length) { throw new StringIndexOutOfBoundsException(srcEnd); } if (srcBegin > srcEnd) { throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); }
    //調用native方法進行數組複製 System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd
- srcBegin); }

2. equals()、equalsIgnoreCase()、regionMatches()、compareTo()、compareToIgnoreCase()、hashCode()

equals()方法用來判斷兩個String是否相等,實現邏輯如下:

 public boolean equals(Object anObject) {
        if (this == anObject) {//如果兩個String是引用同一個String對象,則相等
            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])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

equalsIgnoreCase()忽略大小寫進行判斷,其內部實現是調用regionMatches()方法。

  regionMatches()方法是用來判斷兩個字元串區域是否相等。String中有兩個regionMatches()方法,不同之處在於有一個增加一個boolean值決定是否忽略大小寫進行判斷。具體的實現如下:

 public boolean regionMatches(boolean ignoreCase, int toffset,
            String other, int ooffset, int len) {
        char ta[] = value;
        int to = toffset;
        char pa[] = other.value;
        int po = ooffset;
        if ((ooffset < 0) || (toffset < 0)
                || (toffset > (long)value.length - len)
                || (ooffset > (long)other.value.length - len)) {
            return false;//不滿足以上條件的都返回false
        }
        while (len-- > 0) {
            char c1 = ta[to++];
            char c2 = pa[po++];
            if (c1 == c2) {
                continue;
            }
            if (ignoreCase) {//是否區分大小寫。
                char u1 = Character.toUpperCase(c1);
                char u2 = Character.toUpperCase(c2);
                if (u1 == u2) {
                    continue;
                }   
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                    continue;
                }
            }
            return false;
        }
        return true;
    }

  另外還存在一個判斷兩個字元串區是否相等的方法,但是是區分大小寫的: public boolean regionMatches(int toffset, String other, int ooffset, int len),但是這個方法內部實現沒有復用上面這個方法。

  compareTo()方法是用來比較兩個字元串大小,比較規則為:按字典順序比較兩個字元串。該比較基於字元串中各個字元的 Unicode 值。將此 String 對象表示的字元序列與參數字元串所表示的字元序列進行比較。如果按字典順序此 String 對象在參數字元串之前,則比較結果為一個負整數。如果按字典順序此 String 對象位於參數字元串之後,則比較結果為一個正整數。如果這兩個字元串相等,則結果為 0。具體實現如下:  

 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;//字元不等,返回Unicode差值。
            }
            k++;
        }
        return len1 - len2;//兩個字元串長度,返回長度差值。若為0,表示兩字元串大小相等。
    }

  compareToIgnoreCase()方法實現:String在內部自定義了一個名為CaseInsensitiveComparator的類,實現Comparator,用來比較忽略大小寫的兩個字元串,比較邏輯是,依次取出兩個字元進行忽略大小寫的比較,其餘邏輯和上面類似。

  hashCode()方法返回String的hash值。

3. startWith()、endWith()

startsWith(String prefix)是判斷字元串是不是以某個指定的子字元串開始,返回boolean值。

startsWith(String prefix, int toffset)是判斷字元串從指定的位置開始是否是以指定的字元串開始,返回boolean值。其實現邏輯是取出對於位置的兩個字元,進行判斷。

endsWith(String suffix)是判斷字元串是不是以某個字元串結尾。它的實現邏輯是調用startsWith(String prefix, int toffset)方法,具體實現如下:

 public boolean endsWith(String suffix) {
        return startsWith(suffix, value.length - suffix.value.length);
    }

4. indexOf()、lastIndexOf()

indexOf(int ch):返回指定字元在此字元串中第一次出現處的索引。

indexOf(int ch, int fromIndex):從指定的索引開始搜索,返回在此字元串中第一次出現指定字元處的索引。

lastIndexOf(int ch):返回最後一次出現的指定字元在此字元串中的索引。

lastIndexOf(int ch, int fromIndex):從指定的索引開始搜索,返回在此字元串中最後一次出現指定字元處的索引。

indexOf(String str):返回第一次出現的指定子字元串在此字元串中的索引。

indexOf(String str, int fromIndex):從指定的索引處開始,返回第一次出現的指定子字元串在此字元串中的索引。

lastIndexOf(String str):返回在此字元串中最右邊出現的指定子字元串的索引。

lastIndexOf(String str, int fromIndex):從指定的索引處開始向後搜索,返回在此字元串中最後一次出現的指定子字元串的索引。

以上方法如果沒有找到索引,則返回-1.

5. substring()、concat()、matches()、contains()

substring(int beginIndex):返回一個新的字元串,它是此字元串的一個子字元串。該子字元串始於指定索引處的字元,一直到此字元串末尾。

substring(int beginIndex, int endIndex):返回一個新字元串,它是此字元串的一個子字元串。該子字元串從指定的 beginIndex 處開始,一直到索引 endIndex - 1 處的字元。

concat(String str):將指定字元串聯到此字元串的結尾。

matches(String regex):判斷此字元串是否匹配給定的正則表達式。

contains(CharSequence s):判斷字元串中是否有該字元序列。

6. replace()、replaceFirst()、replaceAll()

replace(char oldChar, char newChar):返回一個新的字元串,用 newChar 替換此字元串中出現的所有 oldChar 。具體實現如下:  

public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

replaceFirst(String regex, String replacement):使用給定的 replacement 字元串替換此字元串匹配給定的正則表達式的第一個子字元串。

replaceAll(String regex, String replacement):使用給定的 replacement 字元串替換此字元串匹配給定的正則表達式的每個子字元串。

7. split()、join()

  String[] split(String regex, int limit):根據匹配給定的正則表達式來拆分此字元串。數控制模式應用的次數,因此影響結果數組的長度。如果該限制 n 大於 0,則模式將被最多應用 n - 1 次,數組的長度將不會大於 n,而且數組的最後項將包含超出最後匹配的定界符的所有輸入。如果 n 為非正,則模式將被應用儘可能多的次數,而且數組可以是任意長度。如果 n 為零,則模式將被應用儘可能多的次數,數組可有任何長度,並且結尾空字元串將被丟棄。

  String[] split(String regex):根據給定的正則表達式的匹配來拆分此字元串。該方法的作用就像是使用給定的表達式和限制參數 0 來調用兩參數 split 方法。

 public String[] split(String regex, int limit) {
        /* fastpath if the regex is a
         (1)one-char String and this character is not one of the
            RegEx's meta characters ".$|()[{^?*+\\", or
         (2)two-char String and the first char is the backslash and
            the second is not the ascii digit or ascii letter.
         */
        char ch = 0;
        if (((regex.value.length == 1 &&
             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
             (regex.length() == 2 &&
              regex.charAt(0) == '\\' &&
              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
              ((ch-'a')|('z'-ch)) < 0 &&
              ((ch-'A')|('Z'-ch)) < 0)) &&
            (ch < Character.MIN_HIGH_SURROGATE ||
             ch > Character.MAX_LOW_SURROGATE))
        {
            int off = 0;
            int next = 0;
            boolean limited = limit > 0;
            ArrayList<String> list = new ArrayList<>();
            while ((next = indexOf(ch, off)) != -1) {
                if (!limited || list.size() < limit - 1) {
                    list.add(substring(off, next));
                    off = next + 1;
                } else {    // last one
                    //assert (list.size() == limit - 1);
                    list.add(substring(off, value.length));
                    off = value.length;
                    break;
                }
            }
            // If no match was found, return this
            if (off == 0)
                return new String[]{this};

            // Add remaining segment
            if (!limited || list.size() < limit)
                list.add(substring(off, value.length));

            // Construct result
            int resultSize = list.size();
            if (limit == 0) {
                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
                    resultSize--;
                }
            }
            String[] result = new String[resultSize];
            return list.subList(0, resultSize).toArray(result);
        }
        return Pattern.compile(regex).split(this, limit);
    }

  String join(CharSequence delimiter, CharSequence... elements):

  String join(CharSequence delimiter, Iterable<? extends CharSequence> elements):這兩個方法是jdk1.8中出現的,類似字元串拼接,不過可以指定連接符delimiter,後面的elements中間使用該連接符連接。具體實現如下:

 public static String join(CharSequence delimiter, CharSequence... elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        // Number of elements not likely worth Arrays.stream overhead.
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);//該方法中會將連接符拼接
        }
        return joiner.toString();
    }

8. 字元串大小寫轉換:

toLowerCase():轉換為小寫

toUpperCase():轉換為大寫

9. 其他方法:

trim():去掉字元串收尾的空白。

toCharArray():將此字元串轉換為一個新的字元數組。

valueOf():返回 某參數的字元串表示形式。就是將其他類型轉換為String類型的一種方式。

intern():當調用 intern 方法時,如果池已經包含一個等於此 String 對象的字元串,則返回池中的字元串。否則,將此 String 對象添加到池中,並且返回此 String 對象的引用。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 聚聚科技是一個剛創立的公司,很小很小,人很少,老闆感覺是個典型的北京小伙兒,戾氣很重,很有個性。筆試題倒是簡單: 1. echo(), print(), print_r()的區別? echo是PHP語言結構, print和print_r是函數。語言結構沒有返回值,函數可以有返回值(即便沒有用) 。 ...
  • JavaMail API使用javax.mail.Message類來表示一封郵件,Message類是一個抽象類,所以我們需要使用其子類javax.mail.internet.MimeMessage類來創建Message類的實例對象,如果我們創建的是一個簡單文本郵件,那麼MimeMessage類就可以 ...
  • 一直以來把資料庫的表轉換成Entity或DTO都是一件讓人頭痛的事情,既浪費時間又很繁瑣,用其他工具生成多少會有一些不盡人意的地方,於是就自己用Swing寫了一個通過資料庫的表生成JavaBean的工具,支持MySQL、Oracle、SQLServce、PostgreSQL,完美支持JPA註解,可... ...
  • Dr.com是城市熱點公司開發的寬頻計費系統,可以控制網路進行管理,認證,計費,限速……許多的高校與企業都有使用。 從接觸到drcom就很感興趣(原因想必大家都懂...) drcom登陸(認證)方式又有很多不同 這裡說下web端登陸的加密方式 ...
  • spider提供了多重安全保障機制,目前主要支持接入握手校驗,報文完整性校驗,報文加密,報文長度檢查四種機制。 接入認證 spider使用兩次握手校驗,其握手流程如下: 簽名AES加密的方式實現。 license信息存儲在classpath*:spider.dat文件中,在程式中固定。 報文完整性校 ...
  • 多線程的實現方法: 繼承Thread類 實現Runnable類 1. 繼承Thread類 繼承Thread類之後,需要覆蓋父類的 public void run() 方法,作為線程的主方法。 所有線程的執行一定是併發的,即:同一個時間段上會有多個線程交替執行。為了達到這樣的目的,絕對不能直接調用ru ...
  • ...
  • 一、開發前準備 1)微信公眾平臺賬號 訂閱號:個人版用戶,每天可以群發一條消息 服務號:企業版用戶,每天可以群發四條消息 2)外網映射工具—花生殼,讓自己本機tomcat伺服器能然外網訪問 與微信對接的url要具備以下條件: 在公網上能夠訪問 埠只支持80埠 下麵是用花生殼做映射: 訪問外網地址 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...