在java中String和StringBuffer的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在java中String和StringBuffer的区别相关的知识,希望对你有一定的参考价值。

StringBuffer比String更加强大,它可以节约内存空间,改变常量的值,保障线程的安全,它必须用new关键字来实例化
其中StringBuffer sbf = new StringBuffer(32);//这不是说创建了字符串的内容,而是说创建的StringBuffer对象的初始容量为32个字符,而String没有此功能String默认为16它有功能比String更强大的方法,如下:

它有方法.append//用于追加字符序列,如:
StringBuffer sbf1 = new StringBuffer("1");
StringBuffer sbf2 = new StringBuffer("2");
sbf1.append(sbf1);//会将sbf2转换,然后放在结尾处此处参数也可以为int类型

修改指定位置的字符.setCharAt,它有两个参数,第一个是位置(从0开始算)第二个是内容

插入字符串.insert,它有两个参数,第一个是位置(从0开始算)第二个是内容。如果用String来操作,则是现将字符串分割成两个,再在创建一个字符串进行操作

删除子字符串.delete(int start, int end)移除自start起至end-1位置的子字符串

其余与String相同

还有一个叫StringBuilder它可以用.reverse();来反序输出字符串

String每次改变值都会在内存中重建一个新的区域来存储,而StringBuffer和StringBuilder每次都只对已占用的内存处存储的结果进行修改,大大提高了效率

String 线程不安全 执行效率低
StringBuffer 线程安全 执行效率中
StringBuilder 线程不安全 执行效率高
参考技术A String是一种强不变类型,它的值一旦被赋予之后,在内存中的相应位置上的值就不会变化了.即便你用String的方法:concat(String str)和replace(char oldChar, char newChar)等等,所返回的值都是新创建的一个String类型,而不是在原内存地址上去更改,因此比如这样的一个赋值:
String s="Hello Baidu";
s=new String("Hello Baidu");

这样在内存中其实是开辟了两个内存空间来存放Hello Baidu,前面那个对象依然留在内存当中,而:
s=s.concat("!");
加上这样一句,s的值变为了Hello Baidu!,在内存中实际上是新创建了一个String对象装Hello Baidu!,而原有的Hello Baidu依然存在

StringBuffer就不同了,它是种可变类型,它的值被赋予之后,在运行期同样可以通过它的方法,如append(String str) 操作内存上的值,而不仅仅是它的引用而已,也就是说同样的对s的值进行修改
StringBuffer s="Hello Baidu";
s.append("!");
这样的操作其实只创建了一个StringBuffer的对象,大大节约了内存的开销

String和StringBuilder和StringBuffer

String简述

字符串广泛应用 在Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。

 

String使用final关键字修饰可以知道String是不可变的类,String中字符数组的长度你定义多少,就是多少,不存在字符数组扩容一说。

内部是final修饰的char[] value,表示String类不可被继承,且value只能被初始化一次。这里的value变量其实就是存储了String字符串中的所有字符。

//String
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
    private final char value[];
    public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }
}
//StringBuilder
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
}

查看类

  java.lang.String :此类不需要导入。

查看构造方法

  String() 创建一个空的字符串对象   String(String original) 根据字符串来创建一个字符串对象   String(char[] value) 通过字符数组来创建字符串对象   String(byte[] bytes) 通过字节数组来构造新的字符串对象   String(byte[] bytes, int offset, int length) 通过字节数组一部分来构造新的字符串对象

通过构造方法创建
  通过
new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同 直接赋值方式创建
  以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象,并在字符串池中维护

常用方法

  

public boolean equals (Object anObject) :将此字符串与指定对象进行比较。
public boolean equalsIgnoreCase (String anotherString) :将此字符串与指定对象进行比较,忽略大小写。
public boolean contains (CharSequence s) :判断参数字符串在当前字符串中是否存在(区分大小写)。存在,返回true,否则,返回false。
public boolean endsWith(String suffix) :测试此字符串是否以指定的后缀结尾(区分大小写)。
public boolean startsWith(String prefix) :测试此字符串是否以指定的前缀开始(区分大小写)
public int length () :返回此字符串的长度。
public String concat (String str) :将指定的字符串连接到该字符串的末尾。
public char charAt (int index) :返回指定索引处的 char值。
public int indexOf (String str) :返回指定子字符串第一次出现在该字符串内的索引。
public int lastIndexOf(String str) :返回指定子字符串最后一次出现的字符串中的索引。 如果不包含,则返回-1public String substring (int beginIndex) :返回一个子字符串,从beginIndex开始截取字符串到字符串结尾。
public String substring (int beginIndex, int endIndex) :返回一个子字符串,从beginIndex到endIndex截取字符串。含beginIndex,不含endIndex。
public char[] toCharArray () :将此字符串转换为新的字符数组。
public byte[] getBytes () :使用平台的默认字符集将该 String编码转换为新的字节数组。
public String toLowerCase() :使用默认语言环境的规则将此 String所有字符转换为小写。public String toUpperCase() :将此 String所有字符转换为大写,使用默认语言环境的规则。
public String replace (CharSequence target, CharSequence replacement) :将与target匹配的字符串使用replacement字符串替换
public String[] split(String regex) :将此字符串按照给定的regex(规则)拆分为字符串数组。
public String trim() :去掉当前字符串的前后空格,并返回一个新字符串,原字符串不变

 

 Java StringBuffer 和 StringBuilder 类——StringBuffer字符串变量、StringBuilder字符串变量

StringBuffer和StringBuilder二者的源码以及append方法,二者都是AbstractStringBuilder的子类,
也都实现了Serializable(可序列化)和CharSequence(char类型的可读序列)接口,AbstractStringBuilder
实现了Appendable(长度可增加)和CharSequence接口。

StringBuffer上使用了synchronized 关键字加了同步锁证明它是线程安全的,而StringBuilder没有使用说明是线程不安全的
//StringBuilder
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
}
    
//StringBuffer
 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
    @Override
    private transient char[] toStringCache;
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
}

//AbstractStringBuilder 
abstract class AbstractStringBuilder implements Appendable, CharSequence{
    char[] value;
    int count;
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
}
  

StringBuilder原理分析

 

    public StringBuilder(int capacity) {
        super(capacity);
    }
        public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }
     public StringBuilder(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }
        @Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
      @Override
    public String toString() {
        // Create a copy, don‘t share the array
        return new String(value, 0, count);
    }
  • 在参数String类型的构造方法中,在本身字符串长度的基础上再增加16个字符长度,作为StringBuilder实例的初始数组容量,并将str字符串 append到StringBuilder的数组中。
  • 这里的toString方法直接new 一个String对象,将StringBuilder对象的value进行一个拷贝,重新生成一个对象,不直接操作StringBuilder的value。
  • StringBuilder没有像String一样去重新new 对象,所以在频繁的拼接字符上省去了new 关键字的StringBuilder,不必每次都要重新开辟新的内存空间,其效率远远高于String类。

StringBuffer原理分析

  StringBuffer是线程安全的高效字符串操作类,在StringBuilder上加了锁机制
  StringBuilder的构造方法、append()和toString()方法

 

总结

  • String 类不可变,内部维护的char[] 数组长度不可变,为final修饰,String类也是final修饰,不存在扩容。字符串拼接,截取,都会生成一个新的对象。频繁操作字符串效率低下,因为每次都会生成新的对象。
  • StringBuilder 类内部维护可变长度char[] , 初始化数组容量为16,存在扩容, 其append拼接字符串方法内部调用System的native方法,进行数组的拷贝,不会重新生成新的StringBuilder对象。它是非线程安全的字符串操作类, 其每次调用 toString方法而重新生成的String对象,不会共享StringBuilder对象内部的char[],会进行一次char[]的copy操作。
  • StringBuffer 类内部维护可变长度char[], 基本上与StringBuilder一致,但其为线程安全的字符串操作类,大部分方法都采用了Synchronized关键字修改,以此来实现在多线程下的操作字符串的安全性。其toString方法而重新生成的String对象,会共享StringBuffer对象中的toStringCache属性(char[]),但是每次的StringBuffer对象修改,都会置null该属性值。

 

 

以上是关于在java中String和StringBuffer的区别的主要内容,如果未能解决你的问题,请参考以下文章

Java中的String和StringBuffer有啥区别?

java中String StringBuilder 和 StringBuffer的联系与区别

JAVA辨析:String,StringBuffer与StringBuilder

String和StringBuilder和StringBuffer

String和StringBuilder和StringBuffer

String,StringBuffer,StringBuilder 的区别是什么