String、StringBuffer与StringBuilder相关知识介绍

String简介

今天闲着没事,重新温故了下string源码,下面主要介绍下String主要方法和实现,以及衍生出的StringBuffer与StringBuilder之间区别与联系。
言归正传了,我们都知道String类在java.lang包中,String类创建一个字符串变量,字符串变量属于对象。String类被声明为final,所以对象创建后不能修改,由0或多个字符组成。

创建:String str = new String("");  /  String str = "";
组成:字符数组 char value[] / 哈希值:int hash

String本身提供了16个构造方法,可以传入不同的参数进行创建对象,本身数据结构为一个字符数组。

String主要方法

  1. length() 获取字符串长度

    直接返回字符数组长度 : value.length

  2. isEmpty() 判断是否为null

    主要判断字符数组长度是否为0 : value.length == 0

  3. charAt(int) 截取一个字符

    直接返回字符数组某索引处值: value[i]

  4. getChars(char,int) 截取多个字符

    使用了带有native声明的方法: System.arraycopy()
    该方法是使用C写的,所以性能上比使用循环高效;
    如果对JNI感兴趣可以看看这篇文章:

    https://www.cnblogs.com/moon1992/p/5260226.html

  5. equal 与 == 比较字符串是否相等

    比较两个字符串:equal主要就是比较两个字符数组每个字符是否相等,
    == 判断两个字符串是否是同一引用了;

  6. compareTo 返回比较值
    这个主要是比较两个字符串的大小了,附上代码:

    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) { //判断k处索引字符是否相等
                    return c1 - c2; //不等,返回两个字符hash差值
                }
                k++;
            }
            //如果前面的字符都相等
            return len1 - len2;  //返回两个字符串的长度差值
        }

    主要看返回值的正负,和0比较 ,当等于0的时候和equal的功能一样了。

  7. startsWith(string) 与 endsWith(string) 判断开始或结尾是否为某字符串

    这个主要就是判断下 字符数组前几个或后几个是否和 传入的字符串一致了

    public boolean startsWith(String prefix, int toffset) {
            char ta[] = value;
            int to = toffset;
            char pa[] = prefix.value;
            int po = 0;
            int pc = prefix.value.length;
            // 判断下传入的字符串是否过长
            if ((toffset < 0) || (toffset > value.length - pc)) {
                return false;
            }
            while (--pc >= 0) { //循环遍历,判读字符数组值了
                if (ta[to++] != pa[po++]) {
                    return false;
                }
            }
            return true;
        }
  8. hashCode() 获取hash值

    这里主要是看下hash值的计算方法:

    public int hashCode() {
            int h = hash;  //字符串hash默认初始为0
            if (h == 0 && value.length > 0) {
                char val[] = value;
                //遍历累加  31*h + 字符hash值
                for (int i = 0; i < value.length; i++) {
                    h = 31 * h + val[i];
                }
                hash = h;
            }
            return h;
        }
  9. indexOf 与 lastIndexOf 判断字符或字串索引位置

    主要逻辑就是 遍历从0或者length-1 索引开始找到和传入的string相同的,返回该位子索引就行了;两个for嵌套就行,如果入参为 char ,一个for就行;

    static int indexOf(char[] source, int sourceOffset, int sourceCount,
                char[] target, int targetOffset, int targetCount,
                int fromIndex) { //indexOf 通用方法
            //判断开始索引位置 是否大于 字符串长度
            if (fromIndex >= sourceCount) {
                return (targetCount == 0 ? sourceCount : -1);
            }
            //判断索引位置是否小于0,赋初始值 0,即索引位置从0开始
            if (fromIndex < 0) {
                fromIndex = 0;
            }
            //入参长度为0
            if (targetCount == 0) {
                return fromIndex;
            }
            //判断的入参初始字符
            char first = target[targetOffset];
            //最大遍历次数 字符串起始位置 + (字符串长度-入参长度)
            int max = sourceOffset + (sourceCount - targetCount);
            //循环遍历开始
            for (int i = sourceOffset + fromIndex; i <= max; i++) {
                //入参第一个字符 与 字符串数组进行匹配,直到第一个相等出现
                if (source[i] != first) {
                    while (++i <= max && source[i] != first);
                }
                if (i <= max) {
                    int j = i + 1;
                    int end = j + targetCount - 1;
                    //如果入参字符串长度大于1,判断后续值是否相等
                    for (int k = targetOffset + 1; j < end && source[j]
                            == target[k]; j++, k++);
    
                    if (j == end) {
                        return i - sourceOffset;
                    }
                }
            }
            return -1;
        }
  10. subString() 截取字符串

    这个实现比较简单,就是截取 开始索引至结束索引这段长度的字符数组,返回一个新的string对象;

  11. concat() 连接字符串

    这里主要用了Arrays.copyOf方法进行数据拷贝,返回的也是新创建的string对象;

  12. replace() 替换子串

    将字符串中和入参一样的子串进行替换,和上面indexOf 实现差不多,只是发现相同的时候进行数据替换,并且一直遍历下去,直到结束;而不是发现相同就返回索引位置;

  13. trim() 前后去空

    两个 while 循环,判断“”之后记录前后索引位置,有变动在调用subString方法进行截取;

  14. valueOf() 转换为string

    这里就有点复杂了,根据传入的入参类型不同实现方法也不同,这里就讲一下object的吧,
    本身代码就一句:return (obj == null) ? “null” : obj.toString();
    object的toString方法计算为:
    getClass().getName() + “@” + Integer.toHexString(hashCode());
    hashCode()也是一个native修饰的方法,感兴趣的可以去找找C实现代码看看;

  15. toLowerCase() 与 toUpperCase() 转换大小写

    字符串的字符数组大小写转换,其实就是 字符的hash进行+32 或者 -32 操作了;

比较String、StringBuffer与StringBuilder

执行速度 StringBuilder > StringBuffer > String

理由: 
String: 不可改变对象
StringBuilder:线程非安全的
StringBuffer:线程安全的

字符串缓冲区被多个线程使用时,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。

总结:

少量拼接或常量 String
单线程 拼接字符串 StringBuilder
多线程 拼接字符串 StringBuffer

具体比较代码或者方法解释就不多说了,可以看看这篇博文:

http://blog.csdn.net/mad1989/article/details/26389541

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值