首页 > 代码库 > java中String、StringBuilder和StringBuffer理解

java中String、StringBuilder和StringBuffer理解

String、StringBuilder和StringBuffer理解

1>String

java.lang.String 类

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

    /**
     * Class String is special cased within the Serialization Stream Protocol.
     *
     * A String instance is written initially into an ObjectOutputStream in the
     * following format:
     * <pre>
     *      <code>TC_STRING</code> (utf String)
     * </pre>
     * The String is written by method <code>DataOutput.writeUTF</code>.
     * A new handle is generated to  refer to all future references to the
     * string instance within the stream.
     */
    private static final ObjectStreamField[] serialPersistentFields =
            new ObjectStreamField[0];
  ......

从以上JDK中String源码可以看出,String类被final修饰,在java中被final修饰的类是不能够被继承的,而且String类中的成员变量都被修饰成final。

而且可以看出String是通过char数组来实现保存字符串的。

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

    public String 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);
    }

    public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

以上是String类的部分成员方法,可以看出他们都不是在原有的String对象上操作的。只要对String对象进行改变,则就会创建新的String对象,对原有的对象并没有改变。

注意:String str1="abc" 和 String str2=new String("abc");有什么区别呢? 代码测试为证:

public class stringTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String str1 = "abc";
        String str2 = new String("abc");
        String str3 = new String("abc");
        String str4 = "abc";
        
        System.out.println(str1 == str2);
        System.out.println(str2 == str3);
        System.out.println(str1 == str4);
    }
}

结果是:

技术分享

所以:string str1="abc"; 这样的语句是在编译时生成了字面常量和字符引用,然后在运行时蒋"abc"保存放到了运行时的常量池中,当下一个语句执行的时候就会从运行时常量池中查找 是否存在,如果存在则将他的引用指向了字面常量,如果没有就新开辟一个空间存放字面常量,并将引用指向他。

  有关new语句创建对象时,都是在堆中进行的,不会检查对象是否存在,所以每一个new语句都会创建一个新的对象。

2>StringBuilder

StringBuilder对String的改变操作是对原有对象进行操作的。

3>StringBuffer (线程安全)

StringBuffer和StringBuilder是类似的,之不过StringBuffer下的方法被snychronized修饰,线程安全。

 

这三个类是各有利弊,应当根据不同的情况来进行选择使用:

当字符串相加操作或者改动较少的情况下,建议使用 String str="hello"这种形式;

当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。

 

java中String、StringBuilder和StringBuffer理解