474-479StringBuffer和StringBuilder类

一、StringBuffer类

package com.day5_21;

/**
 * @author alice_huijing
 * @version 1.0
 */
/*
StringBuffer类是对String类的一个增强
1)原先的字符串是final类型的,但是java.lang.StringBuffer代表
    的是可变的字符序列,可以对字符串内容进行增删。很多方法与String相同
    而StringBuffer是可变长度的。
2)StringBuffer是一个容器
创建一个StringBuffer对象,然后进去看看类图
StringBuffer实现了Serializable接口
父类AbstractStringBuilder实现了Appendable和CharSequence接口
继承Object
3)因为实现了Serializable,所以StringBuffer的对象是可以串行化的

 */
public class StringBufferClass01 {
    public static void main(String[] args) {
        StringBuffer hello = new StringBuffer("hello");
        // 如果StringBuffer这里有内容hello,这个内容是放到什么地方的呢?
        // 在StringBuffer的父类中有char[] value;这样的一个数组
        // 这个value是用于存放字符的,所以
        // 4)char数组value不是一个final类型,该value是存放我们的字符串内容
        //  因此是存放在堆当中的不是常量池,StringBuffer是一个final类不能被继承

        /*
            String与StringBuffer的对比
            1、String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上
            就是更改地址,效率较低//private final char value[];
            2、StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新
            实际上可以更新内容,不用每次更新地址,效率较高//char[] value;这个放到堆当中
            举例说明:
                String的对象是在堆当中,但是其字符串常量是在常量池当中,需要创建新的对象
                StringBuffer对象是在堆当中的,字符串常量也是在堆当中的,首先开辟一大块空间,
                如果空间不够了才会扩容,如果空间足够可以随意添加修改。
            5)因为StringBuffer字符内容是存在char[] value,所以在变化的时候不用每次都更换地址(即不是每次都创建新的对象)
            所以效率高于String
         */
    }
}

package com.day5_21;

/**
 * @author alice_huijing
 * @version 1.0
 */
/*
    StringBuffer的构造器
    1、StringBuffer()
    2、StringBuffer(CharSequence seq)
    3、StringBuffer(int capacity)
    4、StringBuffer(String str)
 */
public class StringBufferClass02 {
    public static void main(String[] args) {
        // 1、创建一个大小为16的char[], 用于存放字符内容
        StringBuffer stringBuffer = new StringBuffer();  // super(16);
        // 2、StringBuffer(CharSequence seq),这个是直接放到char数组当中去了,这个使用不多
        // 3、还可以通过构造器来指定char[]大小
        StringBuffer stringBuffer1 = new StringBuffer(100);
        // 4、第四种是可以传入一个String字符串,通过字符串创建一个StringBuffer,大小是字符串的长度加上16
        StringBuffer hello = new StringBuffer("hello");

        // 5、String和StringBuffer之间的转换
        // 1)将String转换成StringBuffer-第一种
        String str = "hello tom";
        StringBuffer stringBuffer2 = new StringBuffer(str);
        // 将String转换成StringBuffer-第二种
        StringBuffer stringBuffer3 = new StringBuffer();
        stringBuffer3 = stringBuffer3.append(str);

        // 2)StringBuffer转换成为String-第一种
        StringBuffer hello1 = new StringBuffer("hello");
        String s = hello1.toString();
        // StringBuffer转换成String-第二种
        String s1 = new String(hello1);
    }
}

package com.day5_21;

/**
 * @author alice_huijing
 * @version 1.0
 */
/*
    StringBuffer的常见方法
    1、append
    2、delete
    3、replace
    4、indexOf
    5、insert
    6、length
 */
public class StringBufferClass03 {
    public static void main(String[] args) {
        // 1、append添加
        StringBuffer sb = new StringBuffer("hello");
        sb.append(',');  // hello,
        sb.append("张三丰"); // hello,张三丰
        sb.append("赵敏").append(100).append(true).append(10.5); // hello,张三丰赵敏100true10.5
        System.out.println(sb);  // 因为修改的是容器,没有创建新的对象,可以直接对容器进行修改,打印调用的是toString方法

        // 2、delete删除
        sb.delete(11, 14);  // 删除是根据索引来进行删除>=start && <end的字符
        System.out.println(sb);  // 对应这里就是删除100

        // 3、替换replace
        sb.replace(9, 11, "周芷若");  // [9,11)替换成周芷若
        System.out.println(sb);  // 这里相当于将赵敏替换成周芷若

        // 4、indexOf,查找指定的子串第一次出现的索引位置,如果找不到就返回-1
        int indexOf = sb.indexOf("张三丰");
        System.out.println(indexOf);

        // 5、insert,在索引为9的位置插入一个字符串,原来索引为9的内容后移
        sb.insert(9, "赵敏");
        System.out.println(sb);

        // 6、length
        System.out.println(sb.length());  // 统计有多少个字符

    }
}

package com.day5_21;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class StringBufferClass04 {
//    public static void main(String[] args) {
//        /*
//    关于StringBuffer类的课堂测试题:
//    第一题:看看下面的代码输出什么?为什么?
// */
//        String str = null;
//        StringBuffer sb = new StringBuffer();
//        sb.append(str);  // 这里到底是否存在问题需要查看源码
//        /*
//                value[c++] = 'n';
//                value[c++] = 'u';
//                value[c++] = 'l';
//                value[c++] = 'l';
//                将空转换成了null字符串
//         */
//        System.out.println(sb.length());  // 4,因为是null字符串,所以这里显示的是4
//        System.out.println(sb);  // null
//        StringBuffer sb1 = new StringBuffer(str);  // 看构造器的源码super(str.length() + 16); null.产生空指针异常
//        System.out.println(sb1);
//    }

    public static void main(String[] args) {
        /*
            第二题
            输入商品名称和商品价格,要求打印效果示例,使用前面学习的方法完成
            商品名称 商品价格
            手机 123,564,59
            价格的小数点前面每三位使用逗号隔开
            思路分析:
            1、定义一个Scanner对象,接收用户输入的价格String
            2、希望使用到StringBuffer的insert方法,需要将String转换成StringBuffer
            3、然后使用相关方法进行字符串的处理
         */
        String price = "8123564.59";
        StringBuffer sb = new StringBuffer(price);
        for (int i = sb.lastIndexOf(".")-3; i > 0; i -= 3) {
            sb = sb.insert(i, ",");
        }
        System.out.println(sb);
    }
}


二、StringBuilder

package com.day5_21;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class StringBuilderClass05 {

    public static void main(String[] args) {
        // 1、StringBuilder继承了AbstractStringBuilder类
        // 2、实现了Serializable,说明StringBuilder对象是可以串行化的(对象可以在网络中传输,可以放到文件中)
        // 3、StringBuilder是final类,不能被继承
        // 4、StringBuilder对象字符序列仍然是存放到父类当中AbstractStringBuilder的char[] value;
        // 因此,字符序列是堆中
        // 5、StringBuilder的方法,没有做互斥的处理,即没有synchronized关键字,因此在单线程的情况下使用StringBuilder
        StringBuilder stringBuilder = new StringBuilder();
    }
}

/*
    StringBuilder类的基本介绍
    1、一个可变的字符序列,此类提供了一个与StringBuffer兼容的api,但是不能保证
    同步(StringBuilder不是线程安全的)。
    该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的使用。
    如果可能,建议优先采用该类,因为大多数实现中,它比StringBuffer要快。
    2、在StringBuilder上主要的操作是append和insert方法,可以重载这些方法,
    以接收任意类型的数据。
    我们也来看看类图,StringBuilder同样实现了和StringBuffer一样的接口,继承了Object类
 */
package com.day5_21;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class StringBuilderClass06 {
    public static void main(String[] args) {
        // 测试一下String、StringBuffer、StringBuilder之间的一个效率
        String text = "";
        long startTime = 0L;
        long endTime = 0L;
        StringBuffer buffer = new StringBuffer("");
        StringBuilder builder = new StringBuilder("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {
            buffer.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer的执行时间:" + (endTime - startTime));

        startTime = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {
            builder.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder的执行时间:" + (endTime - startTime));

        startTime = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {
            text = text + i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("String的执行时间:" + (endTime - startTime));
    }
}

/*
    String,StringBuffer和StringBuilder的比较
    1、StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而方法也一样
    2、String是不可变字符序列,效率低,但是复用率高
    3、StringBuffer是可变字符序列、效率较高(增删)、线程安全
        StringBuffer源码中很多的方法前面都加上了一个关键字叫做synchronized
        这个是同步的意思,一个线程在操作的时候另外一个线程就不能操作了。
    4、StringBuilder:可变字符序列,效率最高,线程不安全
    5、String使用注意说明:
    String s = "a"; 创建了一个字符串
    s += "b"; // 实际上原来的a字符串对象已经被丢弃,现在又产生了一个字符串s + "b",也就是ab
    如果多次指向这些改变串内容的操作,就会导致大量副本字符串对象存留在内存当中,降低效率,如果这样
    的操作放到循环当中,就会极大影响程序的性能。
    结论就是:如果我们对String做大量修改,就不要使用String

    StringBuffer的执行时间:3
    StringBuilder的执行时间:2
    String的执行时间:1468

    虽然是这样,但是不同的类在不同的地方具有不同的使用场景:
    使用的结论:
    1、如果字符串存在大量的修改操作,一般使用StringBuffer 或者 StringBuilder
    2、如果字符串中存在大量的修改操作,并且单线程的情况,使用StringBuilder
    3、如果字符串中存在大量的修改操作,并且多线程的情况,使用StringBuffer
    4、如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等
 */
posted @ 2025-05-21 11:10  请叫我虾  阅读(11)  评论(0)    收藏  举报