zoukankan      html  css  js  c++  java
  • String、StringBuffer和StringBuilder源码解析

    1.String

    1.1类的定义

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence

    String类在定义时候使用final关键字进行修饰,限制了这个类无法被继承,里面的方法也无法被重写。

    同时它还实现了Serializable接口、Comparable接口,以及CharSequence接口三个接口:

    • Serializable:序列化接口,如果允许对象被序列化需要实现该类。
    • Comparable:比较对象大小的接口,用来定义对象之间如何进行大小的比较。
    • CharSequence:字符序列接口,相比String类,它是一个更为广泛的可读可写字符序列,而String类是只可读的。

    1.2类的成员变

        /** 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类中常用的两个成员变量value、hash。

    • value:字符类型的数组,用来存放我们所保存的字符串,每一个字符串都会被拆开作为字符来进行存储
    • hash:对应字符串的hash值。

    1.3常用方法

    length():返回value数组的长度。

        public int length() {
            return value.length;
        }

    indexOf(str):获取在字符串中某个字符串的起始位置。这里其实也是用的遍历,从指定的开始位置起,一直遍历直到找到目标字符串,或者直到源字符串的最后一位(其实是最后一位减去目标字符串的长度)。

        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,
                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;
        }

    compareTo(str):比较两个字符串的大小,采用的是逐个字符来进行比较(比较ASCII码)。

        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;
                }
                k++;
            }
            return len1 - len2;
        }

    1.4总结

    String类是一个可序列化,可按照字符大小进行排序,不可继承、只读的字符序列类。

    2.StringBuilder

    2.1类定义

    public final class StringBuilder
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence

    StringBuilder和String的定义类似,同样被final关键字修饰,限定了无法被继承,同时继承Serializable和CharSequence两个接口。

    同时最它多继承了一个抽象类AblstractStringBuilder。

    2.2成员变量

    在StringBuilder中没有再定义其他的成员变量,所使用的底层存放数据的变量来自于父类AbstractStringBuilder。

    在AbstractStringBuilder中,定义了三个成员变量

        char[] value;
    
        int count;
    
        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    • value:字符数组,用来存放传入的字符串。
    • count:int类型,记录value中存放元素的长度。
    • MAX_ARRAY_SIZE:静态常量,代指允许value数组的最大长度。

    2.3常用方法

    append(str):相比String只读的属性,StringBuilder允许我们对其进行写操作。但是由于底层存放数据的是一个数组,因此每次都需要进行一个扩容的判断。如果count+入参字符串的长度大于当前数组value的长度,就需要进行扩容,每次扩容后的数组长度=原长度*2+2。

        public AbstractStringBuilder append(String str) {
            if (str == null)
                return appendNull();
            int len = str.length();
            ensureCapacityInternal(count + len);
            str.getChars(0, len, value, count);
            count += len;
            return this;
        }
    
        private void ensureCapacityInternal(int minimumCapacity) {
            // overflow-conscious code
            if (minimumCapacity - value.length > 0) {
                value = Arrays.copyOf(value,
                        newCapacity(minimumCapacity));
            }
        }
    
        private int newCapacity(int minCapacity) {
            // overflow-conscious code
            int newCapacity = (value.length << 1) + 2;
            if (newCapacity - minCapacity < 0) {
                newCapacity = minCapacity;
            }
            return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
                ? hugeCapacity(minCapacity)
                : newCapacity;
        }

    2.4总结

    StringBuilder补充了String只能读不能写的属性,采用对数组扩容的操作,允许程序员对String类型来进行写操作。

    3.StringBuffer

    3.1类定义

     public final class StringBuffer
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence

    StringBuffer的定义与StringBuilder类似,同样继承了AbstractStringBuilder抽象类,实现了Serializable和CharSequence接口。

    3.2成员变量

    StringBuffer的成员变量和StringBuilder一样,同样适用在AbstractStringBuilder中定义好的字符类型数组value和int类型count。

    3.3常用方法

    append(str):与StringBuilder类似的,两个类都是通过调用AbstractStringBuilder中的append(str)方法来添加字符串。

    区别在于StringBuffer的方法定义上多了一个关键字:Synchronized。通过这个关键字,来保证我们对字符串的写操作的线程安全。

        @Override
        public synchronized StringBuffer append(String str) {
            toStringCache = null;
            super.append(str);
            return this;
        }

    toString():和StringBuilder的toString()方法不一样,这里在StringBuffer中就已经完成了对字符数组的复制,如果连续调用toString()方法,实际返回的都是同一个String对象。而在StringBuilder中,由于数组的复制是发生在String类里面,因此每次调用后返回的都是不同的String对象。

        @Override
        public synchronized String toString() {
            if (toStringCache == null) {
                toStringCache = Arrays.copyOfRange(value, 0, count);
            }
            return new String(toStringCache, true);
        }

    3.4总结

    StringBuffer在Stringbuilder实现了字符串写操作的基础上,又添加了对它的线程安全方面的维护,通过查看源码,可见都是通过在方法上添加synchronized关键字来显示的。这样虽然可以保证线程安全,但是也在一定程度上,舍弃了部分性能。不过在jdk1.5之后对锁的优化,新增了偏向锁、轻量级锁后,如果我们对字符串的写操作不涉及多线程的时候,StringBuffer和StringBuilder的资源损耗是几乎类似的。但如果一旦涉及多线程,StringBuffer则能更好的保障我们的线程安全。

    4.总结

    String类是java中定义用来保存一个字符序列的对象,但是对它的操作只有读,而没有写。所有的写操作实际都是返回了一个新的字符串对象。

    StringBuilder类在String类的基础上,增加了对字符序列的写操作,采用底层数组扩容的方式,来允许添加新的字符串,或删除里面原有的字符串。

    StringBuffer类由在StringBuilder类的基础上,既满足了对字符序列的写操作,又保证了操作的线程安全。因此在实际情况下,优先推荐使用StringBuffer类。

    成员变量

    String类型

  • 相关阅读:
    SQLAlchemy(2) -- SQLAlchemy的安装
    SQLAlchemy(1) -- Python的SQLAlchemy和ORM
    http-proxy-middleware及express实现反向代理
    Vue项目中的http请求统一管理
    vue.js中如何使用scss
    Vue 相关开源项目库汇总
    Vue UI组件库
    route按需加载的3种方式:vue异步组件、es提案的import()、webpack的require.ensure()
    Npoi Web 项目中(XSSFWorkbook) 导出出现无法访问已关闭的流
    vuejs 和 element 搭建的一个后台管理界面
  • 原文地址:https://www.cnblogs.com/yxth/p/11443707.html
Copyright © 2011-2022 走看看