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。