Java中StringBuffer简单操作 + 一道经典面试题

来源:
声明:如果我侵犯了任何人的权利,请联系我,我会删除
欢迎高手来喷我

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类型变量的值改变了。

分析:

  1. Java只有值传递,int是基本类型(PrimitiveType),传递的是值,String和StringBuffer是类,ReferenceType(引用类型)​,传递的是对象的引用。

  2. ​int类型值传递。当基本类型的变量被当作参数传递给方法时,JAVA 虚拟机所做的工作是把这个值拷贝了一 份,然后把拷贝后的值传递到了方法的内部。

    ​​在change()函数里k1变量是局部变量,change()函数执行完毕之后,k1的生命周期也就结束,k1的内存地址将被GC回收。k1的改变不会影响到k值的变化。k1和main()函数中的k仅仅只是值相等,是不同的变量,它们指向的内存地址也不一样。

  3. 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属性值,不同于改变局部变量的指向,这里改变了局部变量(对象引用)指向的对象的属性值。

猜你喜欢

转载自blog.csdn.net/qq_45531729/article/details/112253528