String && StringBuffer的区别: 非可变对象一旦创建之后就不能再被改变,可变对象则可以在创建之后被改变。String对象是非可变对象;StringBuffer对象则是可变对象。为获得更佳的性能需要根据实际情况小心谨慎地选择到底使用这两者中的某一个。 String类用来表示那些创建后就不会再改变的字符串,它是不可变的(immutable); StringBuffer类用来表示内容可变的字符串; 例: 1.String对象: String str = "Hello"; str += "World"; // JVM会创建一个临时的StringBuffer类对象,并调用其append()方法完成字符串的拼接,这是因为 String类是不可变的,拼接操作不得不使用StringBuffer类(并且--JVM会将"Hello"和"World"创建为两个新的 String对象)。之后,再将这个临时StringBuffer对象转型为一个String,代价不菲!可见,在这一个简单的一次拼接过程中,我们让程序创建了四个对象:两个待拼接的String,一个临时StringBuffer,和最后将StringBuffer转型成为的String--它不是最初的str,而是最初的str的引用指向了新生成的String对象"HelloWorld"。 2.StringBuffer对象: StringBuffer strBuf = new StringBuffer("Hello"); strBuf.append("World"); // 程序将只产生两个对象:最初的strBuf :"Hello"和拼接时的String("World"),不再需要创建临时的StringBuffer类对象而后还得将其转换回String对象。节省额外的系统开销。
如何选择是使用String还是StringBuffer: 取决于两种情况,第一种情况是需要连接的字符串是在编译期决定的还是在运行期决定的,第二种情况是你使用的是StringBuffer还是String。 1) 第一种情况:编译期决定相对于运行期决定;如: String str = "This " + "is " + "a " + "Java " + "program"; StringBuffer strBuf = new StringBuffer(); strBuf.append("This "); strBuf.append("is "); strBuf.append("a "); strBuf.append("Java "); strBuf.append("program"); 此时,+操作符比StringBuffer.append()方法要快,WHY?这里编译器的优化起了关键作用,编译器简单地在编译期连接多个字符串。它使用编译期决定取代运行期决定,在你使用new关键字来创建String对象的时候也是如此。这里str对象在编译期就决定了而 StringBuffer对象是在运行期决定的。运行期决定需要额外的开销当字符串的值无法预先知道的时候,编译期决定作糜谧址 闹悼梢栽は戎赖氖?候,也就是说String str = "This " + "is " + "a " + "Java " + "program";这段代码在编译时,编译器会对程序作出优化,String str被优化成“This is a Java program”;而StringBuffer strBuf只会在运行时才处理。所以效率是不一样的。(注意,这里的String str = "This " + "is " + "a " + "Java " + "program";与 String str = "Hello"; str += "World";是不一样的); 2) 第二种情况:使用StringBuffer取代String String str = "Hello"; for(int i = 0; i < 40000; i++) { str += "World"; } StringBuffer strBuf = new StringBuffer("Hello"); for(int i = 0; i < 40000; i++) { strBuf.append("World"); } 此时,StringBuffer.append()方法要比+操作符快得多,WHY?原因是两者都是在运行期决定字符串对象,但是+操作符使用不同于StringBuffer.append()的规则;它是通过String和StringBuffer来完成字符串的连接操作的。
另外,在使用StringBuffer时,可以通过StringBuffer的构造函数来设定它的初始化容量,这样可以明显地提升性能。这里提到的构造函数是StringBuffer(int length),length参数表示当前的StringBuffer能保持的字符数量。如: (1)StringBuffer strBuf = new StringBuffer(); for(int i = 0; i < 40000; i++) { strBuf.append("Hello"); } (2)StringBuffer strBuf = new StringBuffer(100000); for(int i = 0; i < 40000; i++) { strBuf.append("Hello"); } 此时,(2) 的效率好于 (1),因为StringBuffer内部实现是char数组,当使用缺省的构造函数来创建StringBuffer对象的时候,因为没有设置初始化字符长度,StringBuffer的容量被初始化为16个字符,也就是说缺省容量就是16个字符。当StringBuffer达到最大容量的时候,它会将自身容量增加到当前的2倍再加2,也就是(2*旧值+2)。 如果使用缺省值,初始化之后接着往里面追加字符,在追加到第16个字符的时候它会将容量增加到 34(2*16+2),当追加到34个字符的时候就会将容量增加到70(2*34+2)。无论何事只要StringBuffer到达它的最大容量它就不得不创建一个新的字符数组然后重新将旧字符和新字符都拷贝一遍。所以总是给StringBuffer设置一个合理的初始化容量值是错不了的,这样会带来立竿见影的性能增益。(2)避免了复制数组的开销。
创建String对象: String str = "Hello"; // JVM先根据内容"Hello"查找对象,如果没找到,则在heap(堆栈)*上创建新对象,并将其赋予str,否则使用已经存在的对象。 String str = new String("Hello"); // 据内不管heap上有没有"Hello"这个对象,JVM都会在heap上创建一个新String对象;此时heap上可能会出现内容相同,地址不同的String对象。 推荐使用String str = "Hello";这种方法创建String类型的对象,这样会使heap中只存在唯一的一个存放"Hello"对象的内存地址;实际上我们不需要多个独立的"Hello"对象,因为要运行它们的话浪费时间+浪费内存。我们也不必因使用new String("Hello");创建了多个”Hello”对象而发愁,可以使用intern()方法来避免在堆内存上创建重复的String对象来改善Java的运行性能。String intern()方法检查字符串对象的存在性,如果需要的字符串已经存在,那么它将会引用指向已经存在的字符串对象而不是重新创建一个。这和使用 String str = "Hello";这种方法创建对象就作用上来说是一致的。使用intern(): String str = new String("Hello"); str = str.intern();
String对象的比较: "==" //比较地址; "equals" //比较内容; String str1 = "a"; String str2 = "a"; String str3 = new String("a"); str1 == str2 // true str1 == str3 // false str1.equals(str2); // true str1.equals(str3); // true
但是StringBuffer类并没有实现Objcet类的Equals方法,所以不能用这个方法来比较两个StringBuffer类的字符串是否相等: StringBuffer strBuf1 = new StringBuffer(“a”); StringBuffer strBuf2 = new StringBuffer(“a”); System.out.println(strBuf1.equals(strBuf2)); 程序输出:false
*这里想对“heap(堆栈)”做一下更正:应该是heap(堆),而非堆栈。 “堆”是一种通用的内存池,用于存放所有的Java对象。当使用“new”实例化一个对象时,编译器会自动在堆里进行存储分配。 C++在堆栈中创建对象,Java对象引用存储在堆栈中;而Java对象并不存储于其中。 堆栈:堆栈指针向下移动,分配新内存,向上移动,释放内存;创建程序时编译器必须知道存储在堆栈中所有数据的确切大小和生命周期,因为要通过代码实现来控制上下移动堆栈指针,这一约束限制了程序的灵活性。而如果是在堆上创建对象,编译器不需要知道从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。
|
三、StringBuffer的用法
描述:在实际应用中,经常回遇到对字符串进行动态修改。这时候,String类的功能受到限制,而StringBuffer类可以完成字符串的动态添加、插入和替换等操作。
1、构造函数。 StringBuffer() :构造一个没有任何字符的StringBuffer类。 StringBuffer(int length) : :构造一个没有任何字符的StringBuffer类,并且,其长度为length。 StringBuffer(String str) :以str为初始值构造一个StringBuffer类。
2、方法。 说明: 1. 所有方法均为public; 2. 书写格式:[修饰符] <返回类型> <方法名([参数列表])> 如: static int parseInt(String s) 表示:此方法(parseInt)为类方法(static),返回类型为(int),方法所需参数为String类型。
1. StringBuffer append(boolean b) 2. StringBuffer append(char c) 3. StringBuffer append(char[] str) 4. StringBuffer append(char[] str, int offset, int len) 5. StringBuffer append(double d) 6. StringBuffer append(float f) 7. StringBuffer append(int i) 8. StringBuffer append(long l) 9. StringBuffer append(Object obj) 10. StringBuffer append(String str) 11. StringBuffer append(StringBuffer sb)
以上的方法都是向字符串缓冲区“追加”元素,但是,这个“元素”参数可以是布尔量、字符、字符数组、双精度数、浮点数、整型数、长整型数对象类型的字符串、字符串和StringBuffer类等。如果添加的字符超出了字符串缓冲区的长度,Java将自动进行扩充。
String question = new String("1+1="); int answer = 3; boolean result = (1+1==3);
StringBuffer sb = new StringBuffer(); sb.append(question); sb.append(answer); sb.append('/t'); sb.append(result);
System.out.println(sb); 结果为: 1+1=3 false
12. int capacity() :返回当前StringBuffer对象(字符串缓冲区)的总空间,而非字符号串的长度。 13. char charAt(int index) :在当前StringBuffer对象中取索引号为index的字符。第一个字符的索引为“0” 14. StringBuffer delete(int start, int end) :删除当前StringBuffer对象中以索引号start开始,到end结束的子串。 15. StringBuffer deleteCharAt(int index) :删除当前StringBuffer对象中索引号为index的字符。 16. void ensureCapacity(int minimumCapacity) :重新设置字符号串缓冲区的总空间。如果minimumCapacity大于当前的总空间,则新的空间被设置:一种结果是minimumCapacity;另一种结果是{“老空间”乘2加2}。
StringBuffer sb1 = new StringBuffer(5); StringBuffer sb2 = new StringBuffer(5);
sb1.ensureCapacity(6); sb2.ensureCapacity(100);
System.out.println( "sb1.Capacity: " + sb1.capacity() ); System.out.println( "sb2.Capacity: " + sb2.capacity() ); 结果为: sb1.Capacity: 12 sb2.Capacity: 100
17. void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) :从当前StringBuffer对象的索引号srcBegin开始,到srcEnd结束的子串,赋值到字符数组dst中,并且从dst的索引号dstBegin开始。
StringBuffer sb = new StringBuffer("I love her!"); char[] i = {'I',' ','l','o','v','e',' ','y','o','u'};
sb.getChars(7,10,i,7);
System.out.println( "sb: " + sb ); 结果为:sb: I love her!
18. int indexOf(String str) :返回当前StringBuffer对象中,第一个满足str子串的位置。 19. int indexOf(String str, int fromIndex) :从当前StringBuffer对象的fromIndex开始查找,返回第一个满足str子串的位置。 20. StringBuffer insert(int offset, boolean b) 21. StringBuffer insert(int offset, char c) 22. StringBuffer insert(int offset, char[] str) 23. StringBuffer insert(int index, char[] str, int offset, int len) 24. StringBuffer insert(int offset, double d) 25. StringBuffer insert(int offset, float f) 26. StringBuffer insert(int offset, int i) 27. StringBuffer insert(int offset, long l) 28. StringBuffer insert(int offset, Object obj) 29. StringBuffer insert(int offset, String str)
以上的方法都是在当前StringBuffer对象中插入一个元素,在索引号offset处插入相应的值。 30. int lastIndexOf(String str) :返回当前StringBuffer对象中,最后一个满足str子串的位置。 31. int lastIndexOf(String str, int fromIndex) :从当前StringBuffer对象的fromIndex开始查找,返回最后一个满足str子串的位置。 32. int length() :返回当前StringBuffer对象(字符缓冲区)中,字符串的长度。注意:此方法与capacity() 不同。 33. StringBuffer replace(int start, int end, String str) :替换当前StringBuffer对象的字符串。从start开始,到end结束的位置替换成str。 34. StringBuffer reverse() :将字符串翻转。
StringBuffer sb = new StringBuffer("0123456789"); System.out.println( "sb.reverse(): " + sb.reverse() ); 结果为:sb.reverse(): 9876543210
35. void setCharAt(int index, char ch) :设置索引号index的字符为ch。 36. void setLength(int newLength) :重新设置字符串缓冲区中字符串的长度,如果newLength小于当前的字符串长度,将截去多余的字符。
StringBuffer sb = new StringBuffer("0123456789"); sb.setLength(5); System.out.println( "sb: " + sb ); 结果为:sb: 01234
37. String substring(int start) :取当前StringBuffer对象中,从start开始到结尾的子串。 38. String substring(int start, int end) :取当前StringBuffer对象中,从start开始到end的子串。 39. String toString() :将当前StringBuffer对象转换成String对象。
|