關(guān)于String內(nèi)的indexOf方法的一些疑問

今天瀏覽了一下java里的String類,發(fā)現(xiàn)一個靜態(tài)方法有點(diǎn)意思磁奖,就是我們常用的indexOf(String str)的底層實(shí)現(xiàn)破加,先看下代碼調(diào)用鏈。

public int indexOf(String str) {
    return indexOf(str, 0);
}
    
public int indexOf(String str, int fromIndex) {
    return indexOf(value, 0, value.length,
            str.value, 0, str.value.length, fromIndex);
}

static int indexOf(char[] source, int sourceOffset, int sourceCount,
        String target, int fromIndex) {
    return indexOf(source, sourceOffset, sourceCount,
                   target.value, 0, target.value.length,
                   fromIndex);
}

/**
 * Code shared by String and StringBuffer to do searches. The
 * source is the character array being searched, and the target
 * is the string being searched for.
 *
 * @param   source       the characters being searched.
 * @param   sourceOffset offset of the source string.
 * @param   sourceCount  count of the source string.
 * @param   target       the characters being searched for.
 * @param   targetOffset offset of the target string.
 * @param   targetCount  count of the target string.
 * @param   fromIndex    the index to begin searching from.
 */
static int indexOf(char[] source, int sourceOffset, int sourceCount,
        char[] target, int targetOffset, int targetCount,
        int fromIndex) {
    if (fromIndex >= sourceCount) {
        return (targetCount == 0 ? sourceCount : -1);
    }
    if (fromIndex < 0) {
        fromIndex = 0;
    }
    if (targetCount == 0) {
        return fromIndex;
    }

    char first = target[targetOffset];
    int max = sourceOffset + (sourceCount - targetCount);

    for (int i = sourceOffset + fromIndex; i <= max; i++) {
        /* Look for first character. */
        if (source[i] != first) {
            while (++i <= max && source[i] != first);
        }

        /* Found first character, now look at the rest of v2 */
        if (i <= max) {
            int j = i + 1;
            int end = j + targetCount - 1;
            for (int k = targetOffset + 1; j < end && source[j]
                    == target[k]; j++, k++);

            if (j == end) {
                /* Found whole string. */
                return i - sourceOffset;
            }
        }
    }
    return -1;
}

底層的字符串匹配的邏輯比較簡單兔港,就是普通的匹配模式:

  1. 查找首字符庸毫,匹配target的第一個字符在source內(nèi)的位置,若查找到max位置還找到押框,則返回-1岔绸;
  2. 若在source匹配到了target的第一個字符,那么在依次比較srouce和target后面的字符橡伞,一直到target的末尾盒揉;
  3. 如果target后面的字符與source都已經(jīng)匹配,則返回在source上匹配到的第一個字符的相對下標(biāo)兑徘,否則返回-1刚盈。

但是仔細(xì)讀代碼會發(fā)現(xiàn)一個問題,就是這里

int max = sourceOffset + (sourceCount - targetCount);

max的計算方式挂脑,max的作用是計算出最大的首字符匹配次數(shù)藕漱,取值范圍應(yīng)該是"max <= sourceCount"欲侮。
所以target字符串的長度是可以不用匹配的,故“sourceCount - targetCount”是沒問題的肋联。
關(guān)鍵的地方是這里加上了sourceOffset威蕉,sourceOffset是source字符串的起始匹配偏移量,即從source的哪個字符開始匹配橄仍。
所以韧涨,根據(jù)代碼里的max計算方式,最終計算出來的max值是會有可能大于sourceCount侮繁。
看下測試代碼:

package string;

/**
 * string test
 */
public class StringTest {

    static int indexOf(char[] source, int sourceOffset, int sourceCount,
                       char[] target, int targetOffset, int targetCount,
                       int fromIndex) {
        if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            return fromIndex;
        }

        char first = target[targetOffset];
        int max = sourceOffset + (sourceCount - targetCount);

        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            if (source[i] != first) {
                while (++i <= max && source[i] != first);
            }

            /* Found first character, now look at the rest of v2 */
            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);

                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        String source = "abcdefghigklmn";
        String target = "n";
        int sourceOffset = 5;
        int targetOffset = 0;

        int index = indexOf(source.toCharArray(), sourceOffset, source.length(), target.toCharArray(), targetOffset, target.length(), 0);
        System.out.println(index);
    }
}

如果target在source內(nèi)可以匹配到返回正確結(jié)果8(結(jié)果8是相對于sourceOffset的結(jié)果虑粥,如果轉(zhuǎn)換成source內(nèi)的位置則是13)。
但是如果target在source內(nèi)匹配不到宪哩,則會拋出java.lang.ArrayIndexOutOfBoundsException異常娩贷,如下:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 14
    at string.StringTest.indexOf(StringTest.java:27)
    at string.StringTest.main(StringTest.java:52)

可見報出越界的下標(biāo)是14,這就是由于max = sourceOffset + (sourceCount - targetCount)引起,計算出的max值為:17锁孟。

所以彬祖,個人認(rèn)為max計算這里是個潛在的BUG,應(yīng)該改為 int max = sourceCount - targetCount;

不過這個方法是一個非public方法罗岖,只在String內(nèi)部調(diào)用涧至,同時也跟蹤了所有對該方法的調(diào)用鏈,都是傳入的默認(rèn)0,在使用時不會出現(xiàn)數(shù)組越界問題桑包。
不知這是開發(fā)者故意為之南蓬,還是其它我未知用意,歡迎大家交流討論Q屏恕W阜健!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弱左,一起剝皮案震驚了整個濱河市窄陡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拆火,老刑警劉巖跳夭,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異们镜,居然都是意外死亡币叹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門模狭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颈抚,“玉大人,你說我怎么就攤上這事嚼鹉》泛海” “怎么了驱富?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匹舞。 經(jīng)常有香客問我褐鸥,道長,這世上最難降的妖魔是什么策菜? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任晶疼,我火速辦了婚禮酒贬,結(jié)果婚禮上又憨,老公的妹妹穿的比我還像新娘。我一直安慰自己锭吨,他們只是感情好蠢莺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著零如,像睡著了一般躏将。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上考蕾,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天祸憋,我揣著相機(jī)與錄音,去河邊找鬼肖卧。 笑死蚯窥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的塞帐。 我是一名探鬼主播拦赠,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼葵姥!你這毒婦竟也來了荷鼠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤榔幸,失蹤者是張志新(化名)和其女友劉穎允乐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體削咆,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牍疏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了态辛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片麸澜。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖奏黑,靈堂內(nèi)的尸體忽然破棺而出炊邦,到底是詐尸還是另有隱情编矾,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布馁害,位于F島的核電站窄俏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏碘菜。R本人自食惡果不足惜凹蜈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忍啸。 院中可真熱鬧仰坦,春花似錦、人聲如沸计雌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凿滤。三九已至妈橄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間翁脆,已是汗流浹背眷蚓。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留反番,地道東北人沙热。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像恬口,于是被迫代替她去往敵國和親校读。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

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

  • 前言 最先接觸編程的知識是在大學(xué)里面,大學(xué)里面學(xué)了一些基礎(chǔ)的知識养铸,c語言雁芙,java語言,單片機(jī)的匯編語言等钞螟;大學(xué)畢...
    oceanfive閱讀 3,068評論 0 7
  • 廢話不多說兔甘,自己進(jìn)入今天的主題 1、面向?qū)ο蟮奶卣饔心男┓矫妫?答:面向?qū)ο蟮奶卣髦饕幸韵聨讉€方面: - 抽象:...
    傳奇內(nèi)服號閱讀 2,349評論 1 31
  • 暑期在家吹著空調(diào)吃著西瓜與在炎炎夏日悶在教室看書鳞滨,我選擇了后者洞焙,為了下半輩子吹空調(diào)吃西瓜
    太陽沒有燈罩閱讀 67評論 0 0
  • 知道一個人的心意,而沒有辦法回復(fù),心情是復(fù)雜的澡匪。有自己不想放棄的部分熔任,也有自己不能回避的部分。姚鵬媽媽一...
    月下柳閱讀 141評論 0 0
  • 今天快樂的時候是什么? 看到簡書文友的留言甸鸟;文字是有生命力的精靈惦费,它能拯救一個人的靈魂,愿您的文字鼓勵更多的人去更...
    盼盼蝸牛漫步閱讀 174評論 0 0