来源:
声明:如果我侵犯了任何人的权利,请联系我,我会删除
欢迎高手来喷我
文章目录
StringBuffer 和String的不同
String是不可变的对象, 因此在每次对String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,性能就会降低。
使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。所以多数情况下推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。
在某些特别情况下, String 对象的字符串拼接其实是被 Java Compiler 编译成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢
StringBuffer的继承关系
StringBuffer的API
构造函数
length长度函数和capacity容量函数
length()是元素的个数:
public synchronized int length() {
//count是元素的个数
return count;
}
capacity:
public synchronized int capacity() {
//value是char[]类型,真正存储元素的地方
return value.length;
}
length是StringBuffer实际分配到的长度,而capacity是StringBuffer的总容量。
StringBuffer sb = newStringBuffer();如果传入的是一个整形,则可以设置capacity的大小而不会改变length的长度,capacity默认是16
StringBuffer sb = newStringBuffer(10);
Sb.append(“ab”);sb.length()为2,sb.capacity()为18;
StringBuffer sb = newStringBuffer();sb.length()为0,sb.capacity()为16
charAt函数
以下实现的都是类似的功能:
getChars和setChar函数
getChars将【srcBegin,srcEnd)之间的chars放在dst【dstBegin~ )里面:
public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
int dstBegin)
{
super.getChars(srcBegin, srcEnd, dst, dstBegin);
}
setChar
public synchronized void setCharAt(int index, char ch) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
toStringCache = null;
value[index] = ch;
}
append函数
substring获取部分函数
delete函数
insert函数
index按位查找函数
reverse翻转函数
public synchronized StringBuffer reverse() {
toStringCache = null;
super.reverse();
return this;
}
toString转String函数
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
经典面试题=考察到int , String 和 StringBuffer的值传递问题
来源:http://blog.sina.com.cn/s/blog_50800ffd0102vvtu.html
public class ReferenceChangeValue {
public static void change(int k1,String s1,StringBuffer sb1){
k1 = 2;
s1 = "a";
//sb1 = new StringBuffer("C");
sb1.append("C");
}
public static void main(String[] args) {
int k = 1;
String s = "A";
StringBuffer sb = new StringBuffer("B");
change(k,s,sb);
System.out.println("k = "+k+" s = "+s+" sb = "+sb);
}
}
程序运行结果:
k = 1 s = A sb = BC
//可以看到,int类型 和 String类型变量的值没有改变,StringBuffer类型变量的值改变了。
分析:
-
Java只有值传递,int是基本类型(PrimitiveType),传递的是值,String和StringBuffer是类,ReferenceType(引用类型),传递的是对象的引用。
-
int类型值传递。当基本类型的变量被当作参数传递给方法时,JAVA 虚拟机所做的工作是把这个值拷贝了一 份,然后把拷贝后的值传递到了方法的内部。
在change()函数里k1变量是局部变量,change()函数执行完毕之后,k1的生命周期也就结束,k1的内存地址将被GC回收。k1的改变不会影响到k值的变化。k1和main()函数中的k仅仅只是值相等,是不同的变量,它们指向的内存地址也不一样。
-
String和StringBuffer等引用类型( ReferenceType,有三种类型:类、接口、和数组)值传递,JAVA 虚拟机会拷 贝一份这个变量所持有的引用,然后把它传递给JAVA 虚拟机为方法创建的局部变量,从而 这两个变量指向了同一个对象。
当一个对象或引用类型变量被当作参数传递时,也是值传递,这个值就是对象的引用,因此JAVA 中只有值传递,没有引用传递。
所以,JAVA虚拟机把对象在堆中保存地址的信息传递给change()函数中的形参变量,使得main()函数中的实参变量以及change()函数中的形参变量均指向同一个地址,但是,仍旧是两个独立的变量,仅有的关联是指向同一堆中的地址。
接下来,分析下程序,String变量s和s1均指向堆中变量s的地址,在change()函数中s1 = “a”; 作用仅仅是改变了局部变量s1(存储在栈中,作用域仅限于change()函数)的指向,指向"a"的内存地址,而main()函数中s变量的指向没有改变,所以change()函数执行完毕后,s1变量被销毁,s的值并没有受到影响。 同样,如果将程序中sb1.append(“C”); 这句话替换为 sb1 = new StringBuffer(“C”); 运行结果则是sb = B,StringBuffer变量sb的值也不会改变,因为局部变量sb1的指向变化不会影响到sb的指向。
那么,sb1.append(“C”); 这句话为什么就能够改变sb1和sb的值呢?那是因为sb1指向sb的地址,执行append()方法 会改变sb地址保存的StringBuffer对象的value属性值,不同于改变局部变量的指向,这里改变了局部变量(对象引用)指向的对象的属性值。