共同学习Java源码--常用数据类型--String(十五)

本文详细解析了Java中String的toLowerCase方法,包括其如何将字符串中的字符转换为小写,处理Unicode字符的逻辑,以及针对特定语言(如土耳其、阿塞拜疆和意大利)的特殊情况。通过分析代码,阐述了方法内部的循环处理和字符转换的实现,帮助读者深入理解Java字符串处理的底层机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    public String toLowerCase(Locale locale) {
        if (locale == null) {
            throw new NullPointerException();
        }


        int firstUpper;
        final int len = value.length;


        /* Now check if there are any characters that need to be changed. */
        scan: {
            for (firstUpper = 0 ; firstUpper < len; ) {
                char c = value[firstUpper];
                if ((c >= Character.MIN_HIGH_SURROGATE)
                        && (c <= Character.MAX_HIGH_SURROGATE)) {
                    int supplChar = codePointAt(firstUpper);
                    if (supplChar != Character.toLowerCase(supplChar)) {
                        break scan;
                    }
                    firstUpper += Character.charCount(supplChar);
                } else {
                    if (c != Character.toLowerCase(c)) {
                        break scan;
                    }
                    firstUpper++;
                }
            }
            return this;
        }


        char[] result = new char[len];
        int resultOffset = 0;  /* result may grow, so i+resultOffset
                                * is the write location in result */


        /* Just copy the first few lowerCase characters. */
        System.arraycopy(value, 0, result, 0, firstUpper);


        String lang = locale.getLanguage();
        boolean localeDependent =
                (lang == "tr" || lang == "az" || lang == "lt");
        char[] lowerCharArray;
        int lowerChar;
        int srcChar;
        int srcCount;
        for (int i = firstUpper; i < len; i += srcCount) {
            srcChar = (int)value[i];
            if ((char)srcChar >= Character.MIN_HIGH_SURROGATE
                    && (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
                srcChar = codePointAt(i);
                srcCount = Character.charCount(srcChar);
            } else {
                srcCount = 1;
            }
            if (localeDependent ||
                srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
                srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
                lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
            } else {
                lowerChar = Character.toLowerCase(srcChar);
            }
            if ((lowerChar == Character.ERROR)
                    || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
                if (lowerChar == Character.ERROR) {
                    lowerCharArray =
                            ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale);
                } else if (srcCount == 2) {
                    resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount;
                    continue;
                } else {
                    lowerCharArray = Character.toChars(lowerChar);
                }


                /* Grow result if needed */
                int mapLen = lowerCharArray.length;
                if (mapLen > srcCount) {
                    char[] result2 = new char[result.length + mapLen - srcCount];
                    System.arraycopy(result, 0, result2, 0, i + resultOffset);
                    result = result2;
                }
                for (int x = 0; x < mapLen; ++x) {
                    result[i + resultOffset + x] = lowerCharArray[x];
                }
                resultOffset += (mapLen - srcCount);
            } else {
                result[i + resultOffset] = (char)lowerChar;
            }
        }
        return new String(result, 0, len + resultOffset);

    }

这个方法将字符串每一个字母转换成小写。

参数是Locale也就是国际化类,如果参数为空,抛出异常。

创建firstUpper变量,用来记录第一个大写字符的下标。创建final变量len记录字符串的长度。

进入名为scan的for循环,循环变量是firstUpper变量,但是for循环括号内不自增。进入循环后获取每一个字符c,先判断c是否在D800和D8FF之间,如果是,则再获取c所在下标元素对应的代码点,获取代码点后,判断该代码点与该代码点转换成小写后的值是否相等如果不等则退出名为scan的for循环。否则firstUpper与相关代码点所占字符数相加,因为有的特殊字符占两个字符长度。

如果c不在D800和D8FF之间,直接判断c与转换为小写后的值是否相等,不等直接退出名为scan的for循环。否则firstUpper自增。

如果名为scan的for循环一直没有被终止,说明都是小写,直接返回本字符串对象即可。

创建一个char数组result,长度为本字符串长度。

创建一个变量resultOffset,用来记录result的下标偏移变化,也就是说计算result数组中哪个下标该写入元素了。

将本字符串value中firstUpper之前的所有元素拷贝到result中。

获取语言,然后创建localeDependent变量,判断语言是否是tr、az、it中的一种,这些分别是土耳其、阿塞拜疆和意大利所用的语言。

定义一个char数组lowerCharArray,接收小写字符。

定义lowerChar、srcChar、srcCount三个变量,分别接收小写的字符,源字符和字符占多少个字符位。

进入for循环,开始遍历源字符串中firstUpper之后的字符。还是先判断字符是否是D800和D8FF之间的字符如果是,那就srcCount为2,否则srcCount就为1。

再判断所遍历的字符是否是上面说的那三种语言中的一种语言的字符,或者是03A3和0130这两个字符,如果是那就调用 ConditionalSpecialCasing进行小写转换,否则直接用Character类的方法转换成小写。

如果转换后的小写字符是错误字符,或转换后的小写字符超过了0x010000这个界限。那么进行如下处理:

如果小写字符是错误字符,则调用ConditionalSpecialCasing的相关方法直接处理本字符串中相应下标的字符,并将结果引用给lowerChararray数组。

如果小写字符并非错误字符且占两个字符的位数,就调用Character类的方法将该小写字符放入result数组中写入的位置是i+resultOffset,返回的是1或2,也就是该字符占几个字符位数,然后再减去srcCount也就是2,然后加到resultOffset中,这个表达式的值是在-1和0之间,也就是resultOffset要么减一要么不变,就是计算放入result数组的是几个元素如果是1个那就需要减一,因为i每次和srcCoutn相加,srcCount是2的话,等于跳了两个元素遍历,实际上result数组却只增加了一个元素。这个不明白就算了别想了,没什么意思。然后继续下一次循环。

如果小写字符既不是错误字符,有不占两位,则直接调用Character类的方法放入lowerCharArray数组中。

然后获取lowercharArray的长度,判断如果该长度大于srcCount,则创建一个char数组result2,长度是result的长度加上lowerCharArray的长度减去srcCount的长度。然后将result拷贝到result2,其实就是扩充result,因为result2比result元素多。

然后再进入一个for循环将lowerChararray的元素赋值到result的相关位置,注意下标有偏移。


如果当初转换成的小写字符没错误,那就直接赋给result的相关位置。

然后继续下一次循环。这个循环看起来很绕,我也不是特别明白,其实就是不同语言的字符占的位置不一样罢了。没什么细纠缠的必要。

然后将result作为String的参数,构建一个新的String对象返回。


    public String toLowerCase() {
        return toLowerCase(Locale.getDefault());
    }

这个方法调用的是上面的方法,采用默认的locale作为参数传进去。

底下有两个toupperCase方法和上面的类似,而且比较繁杂,不细看了,没意义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值