Java中StringBuffer类的基本使用

1. java.lang.StringBuffer类概述

  • StringBuffer是线程安全的可变字符序列.

  • 线程安全 => 同步 => 效率低.

  • StringBuffer是一个类似String的字符串缓冲区.

  • 多线程环境下用StringBuffer, 单线程环境下用StringBuilder.

  • 对于线程安全的简单解释

    • 线程安全 – 同步 – 效率低 – 我在做事时, 不允许别人做这件事.
    • 线程不安全 – 不同步 – 效率高 – 我在做事时, 允许别人也做这件事.
    • 线程的安不安全针对的是多线程环境, 单线程没有安不安全的说法.
    • 若银行账号有1W元,甲乙分别通过银行卡和存折同时刻取1W元,
      线程同步,只有一个人能取到1W;线程不同步,甲乙都能取到1W。
      因此,多线程需要同步,安全;单线程用不同步,效率高。

2. StringBuffer和String的区别

3. StringBuffer的常用构造方法

  1. public StringBuffer();
  2. public StringBuffer(int capacity); 指定容量的字符串缓冲区对象。即要定义的这个字符串的最大长度。不写就默认16个字符.
  3. public StringBuffer(String str); 指定字符串内容的字符串缓冲区对象.
    public static void main(String[] args) {
        //----用无参构造创建对象(常用)----------------------------
        StringBuffer sb1 = new StringBuffer();
        System.out.println(sb1.toString());
        System.out.println("容量:" + sb1.capacity());//16
        System.out.println("长度:" + sb1.length());//0
        
        //--用StringBuffer(int capacity)创建对象-------------
        StringBuffer sb2 = new StringBuffer(50);
        System.out.println(sb2.toString());
        System.out.println("容量:" + sb2.capacity());//50
        System.out.println("长度:" + sb2.length());//0
        
        //--用StringBuffer(String str)创建对象---------------
        StringBuffer sb3 = new StringBuffer("hello");
        System.out.println(sb3.toString());
        System.out.println("容量:" + sb3.capacity());//21=16+5
        System.out.println("长度:" + sb3.length());//5
    }

4. StringBuffer的常用成员方法

4.1 添加功能

  1. public StringBuffer append(xxx); 在字符串末尾把任意类型数据添加到字符串缓冲区,并返回字符串缓冲区对象本身。
  2. public StringBuffer inset(int offset,xxx); 在指定位置把任意类型数据插入到字符串缓冲区,并返回字符串缓冲区对象本身。(注意插入并不是覆盖)
    public static void main(String[] args) {
        //创建字符串缓冲区对象
        /*①*/
        StringBuffer sb1 = new StringBuffer();
        //调用添加数据的方法
        /*②*/
        StringBuffer sb2 = sb1.append("hello");
        System.out.println(sb1);//hello
        System.out.println(sb2);//hello
        System.out.println(sb1 == sb2);//true
    }
    
    /*
     * ①创建一个字符串缓冲区对象sb1(创建一个杯子sb1). 
     * ②调用方法在缓冲区添加字符串hello(往杯子里倒水),
     *  这个方法返回放了字符串的对象sb1(返回装了水的杯子),并赋给了sb2
     * 
     * 因此sb1、sb2都指向同一个字符串缓冲区
     */

    //改进版:
    public static void main(String[] args) {
        //创建字符串缓冲区对象
        StringBuffer sb1 = new StringBuffer();
        //链式编程调用添加数据的方法
        sb1.append("hello").append(123).append('a');
        System.out.println(sb1);//hello123a
    }
    public static void main(String[] args) {
        //创建字符串缓冲区对象
        StringBuffer sb1 = new StringBuffer("helloworld");
        //调用插入数据的方法
        sb1.insert(5, "java");
        System.out.println(sb1); // hellojavaworld
    }

4.2 删除功能

  1. public StringBuffer deleteCharAt(int index); 删除指定位置的字符,并返回删除后的字符串缓冲区对象本身
  2. public StringBuffer delete(int start,int end); 删除从指定位置开始指定位置结束的内容,并返回删除后的字符串缓冲区对象本身。(包左不包右。在java中几乎所有的从指定位置修改数据的方法都是包左不包右)
    public static void main(String[] args) {
        //创建对象
        StringBuffer sb = new StringBuffer("helloworld");
        //调用方法1
        sb.deleteCharAt(3);
        System.out.println(sb);//heloworld
        //调用方法2
        sb.delete(5, 8);
        System.out.println(sb);//helowd
    }
    //删除所有的数据
    public static void main(String[] args) {
        //创建对象
        StringBuffer sb = new StringBuffer("helloworld");
        //调用方法1
        sb.delete(0, sb.length());
        System.out.println(sb);//空
    }
    //字符串缓冲区对象中的内容清空了,可以添加新的内容。
    //杯子中水倒光了,可以重新盛水。

4.3 替换功能

  1. public StringBuffer replace(int start,int end,String str); 把从start开始到end结束的字符串,替换成str。(包左不包右)
    public static void main(String[] args) {
        //创建对象
        StringBuffer sb = new StringBuffer("helloworld");
        //调用方法
        sb.replace(0, 5, "过年好");
        System.out.println(sb);//过年好world
    }

4.4 翻转功能

  1. public StringBuffer reverse();
    public static void main(String[] args) {
        //创建字符串缓冲区对象
        StringBuffer sb = new StringBuffer("ABCDE");
        //调用方法
        sb.reverse();
        System.out.println(sb);//EDCBA
    }

4.5 截取功能

  1. public String substring(int start); 删除从下标start开始的所有字符串.
  2. public String substring(int start,int end); 删除从start开始,到end结束的所有字符串。(包左不包右)
    public static void main(String[] args) {
        //创建字符串缓冲区对象
        StringBuffer sb = new StringBuffer("ABCDE");
        //调用截取方法
        String s = sb.substring(2);
        System.out.println(sb);//ABCDE
        System.out.println(s);//CDE
    }
    //注意返回值类型是String不是StringBuffer
    public static void main(String[] args) {
        //创建字符串缓冲区对象
        StringBuffer sb = new StringBuffer("66HELLO66");
        //调用截取方法
        String s = sb.substring(2, 7);
        System.out.println(sb);//ABCDEFGH
        System.out.println(s);//HELLO
    }

4.6 其他功能

  1. public int capacity(); 返回当前容量。理论值。(杯子的最大容积)若不在构造中声明该字符串缓冲区的容量,默认个16字符。
  2. public int length(); 返回长度(字符数)。实际值。(杯子的实际盛水量)

5. 注意

  • StringBuffer的toString方法默认重写了

  • 不能把字符串的值直接赋给StringBuffer:
    StringBuffer="hello";   ×
    --------------------------------------
    String s="hello";
    StringButter sb=s;   ×
    

6. java.lang.StringBuilder类概述

  • 线程不安全,不同步、但是效率高的可变字符串。
    因为不同步,只能用于单线程使用。
    StringBuffer的所有功能她都有。
    此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。
  • 安不安全指的是多线程情况下;单线程没有安不安全的说法。
    因此多线程用StringBuffer,安全,但是效率慢;
    单线程用StringBuilder,效率高。

7. 关于StringBuffer的题目

##7.1 String和StringBuffer的相互转换(字符串和字符串缓冲区的转换)

  • 为什么进行类之间的转换

    • 我们将A类转换为B类,是为了使用B类的方法,我们可能要的结果是A类型,所以还得转回来。
      向下转型也是这个目的.
  • 我们常用的是String,为了用StringBuffer中的方法,我们需要把String转成StringBuffer,用完方法我们想得到的是String,我们需要把StringBuffer转成String.

  • String→StringBuffer

    • 法一:通过StringBuffer的构造函数

          public static void main(String[] args) {
              String s = "hello";
              StringBuffer sb = new StringBuffer(s);
          }
      
    • 法二:通过append方法

          public static void main(String[] args) {
              String s = "hello";
              StringBuffer sb = new StringBuffer();
              sb.append(s);
          }
      
  • StringBuffer→String

    • 法一:通过String的构造方法

          public static void main(String[] args) {
              StringBuffer sb = new StringBuffer("hello");
              String s = new String(sb);
          }
      
    • 方式二:通过toString方法

          /*
           * StringBuffer的toString方法默认重写了,返回String类型的StringBuffer中的内容
           */
          public static void main(String[] args) {
              StringBuffer sb = new StringBuffer("hello");
              String s = sb.toString();
          }
      

7.2 把数组拼接成各种指定格式的字符串

  • 法一:用字String做拼接

        // 该方法能实现功能,但是浪费内存,不使用
        public static String arrayToString(int[] arr) {
            String s = "";
            s += "[";
            for (int x = 0; x < arr.length; x++) {
                if (x == arr.length - 1)
                    s += arr[x];
                else {
                    s += arr[x];
                    s += ", ";
                }
            }
            s += "]";
            return s;
        }
    
  • 法二:用StringBuffer做拼接

        // 此方法只开辟一块内存空间,效率高
        public static String arrayToString(int[] arr) {
            StringBuffer sb = new StringBuffer();
            sb.append("[");
            for (int x = 0; x < arr.length; x++) {
                if (x == arr.length - 1)
                    sb.append(arr[x]);
                else
                    sb.append(arr[x]).append(", ");
            }
            sb.append("]");
            return sb.toString();
        }
    

7.3 把字符串翻转

  • 法一:用String做翻转拼接

        // 倒序遍历即可 
        public static String method(String s) {
            String result = "";
            char[] chs = s.toCharArray();
            for (int x = chs.length - 1; x >= 0; x--) {
                result += chs[x];
            }
            return result;
        }
    
  • 法二:用StringBuffer的reverse();方法

        //普通版
        public static String method(String s) {
            StringBuffer sb = new StringBuffer(s);
            sb.reverse();
            return sb.toString();
        }
    
        //改进版
        public static String method(String s) {
            return new StringBuffer(s).reverse().toString();
        }
    

7.4 判断一个字符串是否是对称字符串

  • 法一:挨个比较

        /*
         * 分析:
         * 第一个和最后一个比较;
         * 第二个和倒数第二个比较;
         * ...
         * 比较的次数是长度除以2
         */
        
        //普通版
        public static boolean method1(String s) {
            //先把字符串转成字符数组
            char[] chs = s.toCharArray();
            for (int start = 0, end = chs.length - 1; start <= end; start++, end--) {
                if (chs[start] != chs[end]) {
                    return false;
                }
            }
            return true;
        }
    
        //改进版
        public static boolean method2(String s) {
            boolean flag = true;
            //先把字符串转成字符数组
            char[] chs = s.toCharArray();
            for (int start = 0, end = chs.length - 1; start <= end; start++, end--) {
                if (chs[start] != chs[end]) {
                    flag = false;
                    break;
                }
            }
            return flag;
        }
    
  • 法二:用字符串缓冲区的翻转功能

        public static boolean method(String s) {
            return new StringBuffer(s).reverse().toString().equals(s);
        }
    

7.5 String StringBuffer StringBuilder 的区别

  • 思路:
      1. String与StringBuffer/StringBuilder的区别
      2. StringBuilder与StringBuffer的区别
      3. 原理.
  • 回答
    • 字符串就是多个字符的集合, Java中有两种字符串, 一种是不可变字符串String, 另一种是可变字符串StringBuilder/StringBuffer
    • String是一个常量, 是不可变的, 所以对于每次进行拼接和赋值操作, 都会创建一个新的String对象;
      StringBuffer和StringBuilder都是可变的, 当进行字符串拼接的时候使用append方法, 操作的是同一个对象, 因此在拼接字符串方面, StringBuilder/StringBuffer的性能高于String.
    • StringBuilder是线程不安全的, StringBuffer是线程安全的, 因此StringBuilder的效率高于StringBuffer.
    • 原理
      • String类是final修饰的, String类的底层是char[ ] 也是被final修饰的. 因此使用String进行字符串的截取或拼接时, 都会生成一个新的对象, 因此效率低下.
      • StringBuilder底层是可变长度的char[ ] , 初始化数组容量为16, 可以扩容, 其append()方法拼接字符串时内部调用System的native方法, 进行数组的拷贝, 不会重新生成新的StringBuilder对象.

7.6 String和StringBuffer分别作为参数传递

  • 实际上这个问题问的是java到底是值传递还是引用传递.

  • java中只有值传递, 基本数据类型传递的是栈内存中的值, 引用数据类型传递的是引用变量中存储的对象的地址值. 引用变量不能被改变, 即引用变量中存储的对象的地址值不能被改变, 即引用变量不能指向另一个新的对象, 但是引用变量指向的对象的内容可以被改变.

package cn.king.demo01;

public class Demo09 {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "world";
        // hello--------------world
        System.out.println(s1 + "--------------" + s2);
        change(s1, s2);
        // hello--------------world
        System.out.println(s1 + "--------------" + s2);

        System.out.println("--------------------------");
        
        StringBuffer sb1 = new StringBuffer("hello");
        StringBuffer sb2 = new StringBuffer("world");
        // hello--------------world
        System.out.println(sb1 + "--------------" + sb2);
        change(sb1, sb2);
        // hello--------------worldworld
        System.out.println(sb1 + "--------------" + sb2);
    }

    private static void change(StringBuffer sb1, StringBuffer sb2) {
        sb1 = sb2;//s2的引用赋给了s1
        sb2.append(sb1);//调用方法在s2后面添加hello
    }

    private static void change(String s1, String s2) {
        s1 = s2;//s2的引用赋给了s1
        s2 = s1 + s2;//先开辟空间盛放s1+s2的和,再让s2的引用指向这个空间
    }

    /*
     * java中只有值传递, 形参的改变不会影响实参.
     * 在change(String s1, String s2)中, 我们传进去的是
     * s1. 我们并没有改变s1这个引用, 而是改变了这个引用指向的对象的内容. 
     * 也就是说, 我们不能将s1指向一个新的对象, 即s1不会被改变, s1中存储的对象的地址值不会改变.  
     * 但是我们能改变s1指向的对象的内容. 
     */
}

7.7 将字符串中的字符进行排序

package cn.king.demo01;

/*
 * 把字符串中的字符进行排序。
 * 		举例:"dacgebf"
 * 		结果:"abcdefg"
 *
 * 分析:
 * 		A:定义一个字符串
 * 		B:把字符串转换为字符数组
 * 		C:把字符数组进行排序
 * 		D:把排序后的字符数组转成字符串
 * 		E:输出最后的字符串
 */
public class Demo09 {
    public static void main(String[] args) {
        // 定义一个字符串
        String s = "dacgebf";

        // 把字符串转换为字符数组
        char[] chs = s.toCharArray();

        // 把字符数组进行排序
        bubbleSort(chs);

        //把排序后的字符数组转成字符串
        String result = String.valueOf(chs);

        //输出最后的字符串
        System.out.println("result:" + result);
    }

    // 冒泡排序
    private static void bubbleSort(char[] chs) {
        for (int x = 0; x < chs.length - 1; x++) {
            for (int y = 0; y < chs.length - 1 - x; y++) {
                if (chs[y] > chs[y + 1]) {
                    char temp = chs[y];
                    chs[y] = chs[y + 1];
                    chs[y + 1] = temp;
                }
            }
        }
    }
    
}
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值