java String, StringBuffer,StringBuilder

来源:互联网 发布:领淘宝内部优惠券软件 编辑:程序博客网 时间:2024/05/21 06:16

面试题: String,StringBuffer,StringBuilder的区别?

1:String是不可改变的量,声明的内容不可以修改,而StringBuffer和StringBuilder都是可变字符串序列,声明的内容可以修改;
2:StringBuffer是同步方法,属于线程安全操作,StringBulder是异步方法,属于非线程安全操作;

使用场景:

使用 String 类的场景:在字符串不经常变化的场景中可以使用 String 类,例如常量的声明、少量的变量运算。

使用 StringBuffer 类的场景:在频繁进行字符串运算(如拼接、替换、删除等),并且运行在多线程环境中,则可以考虑使用 StringBuffer,例如 XML 解析、HTTP 参数解析和封装。

使用 StringBuilder 类的场景:在频繁进行字符串运算(如拼接、替换、和删除等),并且运行在单线程的环境中,则可以考虑使用 StringBuilder,如 SQL 语句的拼装、JSON 封装等。

分析:

在性能方面,由于 String 类的操作是产生新的 String 对象,而 StringBuilder 和 StringBuffer 只是一个字符数组的扩容而已,所以 String 类的操作要远慢于 StringBuffer 和 StringBuilder。

简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象。所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。

而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:

1: String S1 = “This is only a" + “ simple" + “ test";2: StringBuffer Sb = new StringBuilder(“This is only a").append(“ simple").append(“ test");

你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个

String S1 = “This is only a" + “ simple" + “test";

源码:

String,StringBuffer,StringBuilder都实现了CharSequence接口。

public interface CharSequence{int length();// return the char value at the specified indexchar charAt(int index);// return a new CharSequence that is a subsequence// of this sequence.CharSequence subSequence(int start, int end);public String toString();}

String的源码

public final class String{private final char value[]; // used for character storageprivate int the hash; // cache the hash code for the string}

成员变量只有两个:
final的char类型数组
int类型的hashcode

构造函数

public String()public String(String original){this.value = original.value;this.hash = original.hash;  }public String(char value[]){ this.value = Arrays.copyOf(value, value.length); }public String(char value[], int offset, int count){// 判断offset,count,offset+count是否越界之后this.value = Arrays.copyOfRange(value, offset, offset+count);}

这里用到了一些工具函数
copyOf(source[],length); 从源数组的0位置拷贝length个;
这个函数是用System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength))实现的。

copyOfRange(T[] original, int from, int to)。

构造函数还可以用StringBuffer/StringBuilder类型初始化String,

public String(StringBuffer buffer) {    synchronized(buffer) {        this.value = Arrays.copyOf(buffer.getValue(), buffer.length());    }}public String(StringBuilder builder) {    this.value = Arrays.copyOf(builder.getValue(), builder.length());}

除了构造方法,String类的方法有很多,
length,isEmpty,可以通过操作value.length来实现。
charAt(int index):
通过操作value数组得到。注意先判断index的边界条件

public char charAt(int index) {    if ((index < 0) || (index >= value.length)) {        throw new StringIndexOutOfBoundsException(index);    }    return value[index]; }

getChars方法

public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { \\边界检测 System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); }

equals方法,根据语义相等(内容相等,而非指向同一块内存),重新定义了equals

public boolean equals(Object anObject) {    if (this == anObject) {        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;}

如果比较的双方指向同一块内存,自然相等;(比较==即可)
如果内容相等,也相等,比较方法如下:
首先anObject得是String类型(用关键字instanceof)
然后再比较长度是否相等;
如果长度相等,则挨个元素进行比较,如果每个都相等,则返回true.

还有现成安全的与StringBuffer内容比较
contentEquals(StringBuffer sb),实现是在sb上使用同步。

compareTo():
如果A大于B,则返回大于0的数;
A小于B,则返回小于0的数;
A=B,则返回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;        }        k++;    }    return len1 - len2;}

regionMatches:如果两个字符串的区域都是平等的,

public boolean regionMatches(int toffset, String other, int ooffset,        int len) {//判断边界条件        while (len-- > 0) {        if (ta[to++] != pa[po++]) {            return false;        }    }        }public boolean regionMatches(boolean ignoreCase, int toffset,        String other, int ooffset, int len) {    while (len-- > 0) {        char c1 = ta[to++];        char c2 = pa[po++];        if (c1 == c2) {            continue;        }        if (ignoreCase) {            // If characters don't match but case may be ignored,            // try converting both characters to uppercase.            // If the results match, then the comparison scan should            // continue.            char u1 = Character.toUpperCase(c1);            char u2 = Character.toUpperCase(c2);             if (u1 == u2) {                continue;            }            // Unfortunately, conversion to uppercase does not work properly            // for the Georgian alphabet, which has strange rules about case            // conversion.  So we need to make one last check before            // exiting.            if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {                continue;            }        }        return false;    }    return true; }

startsWith(String prefix, int toffset)
startsWith(String prefix)
endsWith(String suffix)

{return startsWith(suffix, value.length          - suffix.value.length);      }

substring(int beginIndex,int endIndex)
除了条件判断:

 return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);

字符串连接concat(String str)

    int otherLen = str.length();    if (otherLen == 0) {        return this;    }    int len = value.length;    char buf[] = Arrays.copyOf(value, len + otherLen);    str.getChars(buf, len);    return new String(buf, true);

对于StringBuffer和StringBuilder StringBuffer 和 StringBuilder 都是继承于 AbstractStringBuilder, 底层的逻辑(比如append)都包含在这个类中。

public AbstractStringBuilder append(String str) {    if (str == null) str = "null";    int len = str.length();    ensureCapacityInternal(count + len);//查看使用空间满足,不满足扩展空间    str.getChars(0, len, value, count);//getChars就是利用native的array copy,性能高效    count += len;    return this;}

StringBuffer 底层也是 char[], 数组初始化的时候就定下了大小, 如果不断的 append 肯定有超过数组大小的时候,我们是不是定义一个超大容量的数组,太浪费空间了。就像 ArrayList 的实现,采用动态扩展,每次 append 首先检查容量,容量不够就先扩展,然后复制原数组的内容到扩展以后的数组中.

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 被金融公司骗了怎么办 天猫品牌方投诉怎么办 淘宝卖家售假被扣了12分怎么办? 淘宝店被投诉了怎么办 淘宝商品被投诉侵权怎么办 淘宝小二胡乱判怎么办 淘宝卖家不干了怎么办 花呗剩下的钱怎么办 蚂蚁花呗无法使用怎么办 淘宝不能用花呗怎么办 淘宝号给冻结了怎么办 淘宝买家号封了怎么办 拼多多商家盗图怎么办 被拼多多盗图了怎么办 淘宝盗用图片被投诉怎么办 淘宝别人盗用我的图片怎么办 淘宝盗图申诉原图过大怎么办 淘宝别人举报我盗用图片怎么办 淘宝卖家被投诉盗图怎么办 淘宝卖家被投诉卖假货怎么办 淘宝买到假货卖家不承认怎么办 被投诉盗图扣2分怎么办 拼多多盗淘宝图怎么办 微信视频清理了怎么办 牛仔短裤买大了怎么办 淘宝图片打开变大了怎么办 同城换公司社保怎么办 劳务不给交社保怎么办 好多工厂外包工不交社保怎么办 外包公司没有交社保怎么办 外包公司不给交社保怎么办 银行取100万现金怎么办 给老外发警告信后怎么办 照片上传是歪的怎么办 日亚不能直邮的怎么办 电话信息被卖了怎么办 被亚马逊跟卖了怎么办 玉米出芽后土壤不够湿怎么办 雨伞请输入授权码怎么办 网页放手机端后看不了怎么办 微信收款码存在违法行为怎么办