JAVA-StringBuilder和StringBuffer

一、认识String类

1.认识

String在Java中是字符串类型,但与其他类型不同。它是一个类,可以创建对象的类。与int、char等自待类型有些许不同。但它仍然是java提供的一种类型。

 类中有4个属性,这里主要认识一下value属性。它是实际存放字符串的引用。那么我们来看一下源码:

2.String的不可变性

2.1 final

  1. 被final修饰的类,不能被继承。“断子绝孙了”
  2. 被final修饰的方法,不能被重写
  3. 被final修饰的变量,变量的值不能修改
  4. 被final修饰的引用,其对应的引用 不能指向其他(引用/对象),但是指向引用的值是可以更改的。

被final修饰的引用,不可改变指向的(引用 / 对象)。但是我们看到array[0] = 10;没有报错,也就是元素不受影响。

看一下这个内存图,final实际修饰的是array指向的地址,把他作为常量。那为什么value数组还是不可以改变呢?

我们看Java源码对String类加上了final,只是String类不能被继承了。但对于改变value数组没有什么关系。即便value数组也加上了final,不能指向新的数组,很多人说是这个原因其实是错误的,因为改变数组里面的值是不受影响的。

真正对String对象不能改变的原因是:

凡是对String有改变的方法,都是对一个新的String进行操作,最后返回一个新改变后的String对象,类似对一个副本操作,最后直接用副本了。这是设计Sting时就已经写好了的。

为什么 String 要设计成不可变的?(不可变对象的好处是什么?) 

1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.

2. 不可变对象是线程安全的.

3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中.

这样会有一个非常大的问题,有这样一个代码:

public static void main(String[] args) {
        String array = "a";

        for (int i = 0; i < 1000; i++) {
            //他在这里会不停的发生创建新的对象
            //并进行拼接
            //然后再返回新的对象
            array += i;
        }

        System.out.println(array);
    }

这会大大提升时间空间复杂度

那么以后在使用字符串并且,对字符串进行大量操作,或者不想创建新的String类的时候可以使用StringBuilder和StringBuffer

二、StringBuilder和StringBuffer

1.StringBuilder和Strinig的区别

这里使用StringBuilder进行对比

正常使用StirngBuilder进行拼接:

public static void main(String[] args) {
        StringBuilder s = new StringBuilder("a");
        for (int i = 0; i < 1000; i++) {
            s.append(i);//想当与String的+=
        }
        System.out.println(s.toString());
}

用StringBuilder模拟Stirng进行拼接:

    public static void main(String[] args) {
        StringBuilder s1 = new StringBuilder("a");
        for (int i = 0; i < 1000; i++) {
            StringBuilder tmp = new StringBuilder("");
            tmp = s1.append(i);
        }
        System.out.println(s1.toString());
        
    }

创建类本来就是一个复杂的过程,如果使用String他会创建1000次,那速度肯定是大大降低。

StringBuffer也是跟StringBuilder相同的操作,那StringBuilder和StringBuffer有哪些区别呢?这也是面试常考题

2.String、StringBuffer、StringBuilder的区别

  1. String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
  2. StringBuffer与StringBuilder大部分功能是相似的
  3. StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作

这个第3项给大家解释一下:想要真正了解这个东西需要多线程的理解,这里给大家简单解释一下。

一边看图一边看我解释:

厕所可以看作是一种资源吧

StringBuffer更像家里的厕所,是有锁的。你在上厕所(你在使用资源)别人是进不来的。

StirngBuilder更像是公共场所,没有锁想进来就进来,那肯定没有家里的厕所有安全感。

所以:StringBuffer是安全的,StringBuilder是不安全的。但目前我们写的程序都是单线程的

3.String、StringBuffer、StringBuilder的运行时间区别

使用System.currentTimeMillis()方法可以获取当前时间的一个毫秒数。

用 当前时间-指向前时间 = 时间差

public static void main(String[] args) {
        long start = System.currentTimeMillis();//获得当前时间毫秒数
        String s = "";
        for(int i = 0; i < 100000; ++i){
            s += i;
        }
        long end = System.currentTimeMillis();
        System.out.println("String" + (end - start));

        start = System.currentTimeMillis();
        StringBuffer sbf = new StringBuffer("");
        for(int i = 0; i < 100000; ++i){
            sbf.append(i);
        }
        end = System.currentTimeMillis();
        System.out.println("StringBuffer" + (end - start));

        start = System.currentTimeMillis();
        StringBuilder sbd = new StringBuilder();
        for(int i = 0; i < 100000; ++i){
            sbd.append(i);
        }
        end = System.currentTimeMillis();
        System.out.println("StringBuilder" + (end - start));

}

 结果:

可以看到String与StirngBuilder和StringBuffer的区别是巨大的。但这里并没有体现出StirngBuilder和StringBuffer之间的差距,可能是现在做了优化。不过在不涉及多线程的时候推荐使用StirngBuilder要更快一点。

三、StringBuilder和StringBuffer的常用方法

想要了解String常用方法的可以看我这篇博客:String类和String类常用方法-优快云博客

1. StringBuff append(String str) 拼接字符串

StringBuff append(String str)在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、 double、float、int、long、Object、String、StringBuff的变量
public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("");
        int[] arr = new int[]{1,2,3,4,5};
        stringBuilder.append("a");
        stringBuilder.append(1);
        stringBuilder.append(1.5);
        stringBuilder.append('c');
        for (int a: arr) {
            stringBuilder.append(a);
        }
        System.out.println(stringBuilder.toString());//a11.5c12345
}

2.char charAt(int index) 获取index位置的字符

  public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("hello");
        System.out.println(stringBuilder.charAt(0));//h
        System.out.println(stringBuilder.charAt(-1));//异常
        System.out.println(stringBuilder.charAt(stringBuilder.length()));//异常
  }

3.int length() 获取字符串的长度

 public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("hello");
        System.out.println(stringBuilder.length());//5
 }

4.int capacity() 获取底层保存字符串空间总的大小

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("hello");
        System.out.println(stringBuilder.capacity());//21
}

5.void ensureCapacity(int mininmumCapacity) 扩容

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("hello");
        System.out.println(stringBuilder.capacity());//21
        stringBuilder.ensureCapacity(30);
        System.out.println(stringBuilder.capacity());//44 = 21 * 2 + 2
}

6.void setCharAt(int index, char ch) 将index位置的字符设置为ch

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("hello");
        stringBuilder.setCharAt(2,'a');//注意要输入char类型
        System.out.println(stringBuilder);//healo
}

indexOf函数找不到相应的字符串返回-1

7.int indexOf(String str) 返回str第一次出现的位置

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaabb");
        System.out.println(stringBuilder.indexOf("bb"));//2
}

8.int indexOf(String str, int fromIndex) 从fromIndex位置开始查找str第一次出现的位置

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaabb");
        System.out.println(stringBuilder.indexOf("bb",4));//8
}

9.int lastIndexOf(String str) 返回最后一次出现str的位置

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaabb");
        System.out.println(stringBuilder.lastIndexOf("aa"));//6
}

原理是从后往前找

10.int lastIndexOf(String str, int fromIndex) 从fromIndex位置开始找str最后一次出现的位置

原理是从指定位置从后向前找
public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaabbaa");
        System.out.println(stringBuilder.lastIndexOf("aa",5));//0
        System.out.println(stringBuilder.lastIndexOf("ac",5));//-1找不到
}

11.StringBuff insert(int offset, String str) 在offset位置插入:八种基类类型 & String类型 & Object类型数据

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaabbaa");
        //aaxxxbbccaabbaa
        //不会覆盖原有字符,原位置字符全部往后移
        System.out.println(stringBuilder.insert(2, "xxx"));

        //aaxxxbbccaabbaaxxx,证明可以当追加函数使用
        System.out.println(stringBuilder.insert(stringBuilder.length(), "xxx"));

        //报错
        //说明,要紧跟字符串末尾追加
        System.out.println(stringBuilder.insert(stringBuilder.length()+1, "xxx"));

    }

12.StringBuffer deleteCharAt(int index) 删除index位置字符

 public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaa");
        System.out.println(stringBuilder.deleteCharAt(2));//aabccaa

 }

13.StringBuffer delete(int start, int end) 删除[start, end)区间内的字符

注意:左开右闭[ ,)

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaa");
        System.out.println(stringBuilder.delete(2, 4));//aaccaa
}

14.StringBuffer replace(int start, int end, String str) 将[start, end)位置的字符替换为str

 注意:左开右闭[ ,)

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaa");
        System.out.println(stringBuilder.replace(2, 4,"xx"));//aaxxccaa
        System.out.println(stringBuilder.replace(2, 
                            stringBuilder.length() + 1,"xx"));//aaxx
}

最后一种虽然可以指向成功但绝对不建议这么写

15.String substring(int start) 从start开始一直到末尾的字符以String的方式返回 

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaa");
        System.out.println(stringBuilder.substring(2));//bbccaa
        System.out.println(stringBuilder.substring(stringBuilder.length()));//什么都不打印
        System.out.println(stringBuilder.substring(stringBuilder.length() + 1));//报错
}

16.String substring(int start,int end) 将[start, end)范围内的字符以String的方式返回

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaa");
        //这里不报错是因为左开,右闭
        System.out.println(stringBuilder.substring(2, stringBuilder.length()));//bbccaa
}

17. StringBuffer reverse() 反转字符串

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaa");
        //这里不报错是因为左开,右闭
        System.out.println(stringBuilder.reverse());//aaccbbaa
}

18.String toString() 将所有字符按照String的方式返回

public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("aabbccaa");
        //StringBuilder 以 String 类型返回
        System.out.println(stringBuilder.toString());//aabbccaa
}

这里要着重讲一下,原本是StringBuilder类型,要转换为String类型,就可以用toString。

 注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:

  • String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
  • StringBuilder变为String: 调用toString()方法。

四、面试题

1.

String str = new String("ab"); // 会创建多少个对象
1.会创建一个对象

String str = new String("a") + new String("b"); // 会创建多少个对象
2.a创建一个对象 + b创建一个对象 + 将他们拼接起来需要一个对象 = 3个对象

一共创建了4个对象

 2.String、StringBuffer、StringBuilder的区别

  • String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
  • StringBuffer与StringBuilder大部分功能是相似的 StringBuffer采用同步处理,属于线程安全操作;
  • 而StringBuilder未采用同步处理,属于线程不安全操 作
<think>好的,用户问的是在StringBuilder前面加元素,也就是在字符串的开头插入内容。首先,我得回忆一下StringBuilder的基本操作。StringBuilder通常用于高效地操作字符串,特别是频繁的修改,比如追加、插入、删除等。用户可能已经知道如何追加到末尾,但这里需要在前面插入,所以需要用到Insert方法。 接下来,我要确认StringBuilder的Insert方法的具体用法。Insert方法有多种重载,可以插入不同类型的数据,但位置参数是关键。插入到最前面的话,位置应该是0。例如,sb.Insert(0, "插入的内容")。这时候可能会有性能问题需要考虑,因为每次在前面插入都需要移动后面的所有字符,数据量大时会影响效率。 然后,用户可能需要具体的示例代码来理解如何操作。应该提供一个简单的例子,比如先追加一些元素,再演示在前面插入,并展示结果。同时,需要提醒用户注意性能,如果频繁在头部插入,可能需要考虑其他数据结构,比如链表。 还要考虑用户的实际使用场景。如果用户处理的字符串很大,或者需要频繁在前面插入,那么StringBuilder可能不是最优选择。这时候可以建议使用LinkedList或者List,在头部插入效率更高。但如果只是偶尔操作,StringBuilder的Insert方法还是可行的。 另外,需要检查是否有常见的错误,比如索引越界。确保用户知道插入的位置0是有效的,即使StringBuilder当前为空,插入0的位置也是合法的,因为这会自动变成第一个元素。 总结下来,回答的结构应该先介绍StringBuilder的基本情况,然后介绍Insert方法的使用,给出示例代码,再讨论性能问题使用场景的建议。确保语言简洁明了,适合不同层次的用户理解。</think>在Java中,若要在`StringBuilder`的头部(即字符串开头)插入元素,可以使用其提供的`insert()`方法。下面分步骤说明: --- ### 一、实现原理 `StringBuilder`底层是可变字符数组,调用`insert(0, str)`时: 1. 将原有字符向后移动 2. 在数组头部插入新内容 3. 自动扩容(若空间不足) --- ### 二、具体语法 ```java // 语法格式 StringBuilder sb = new StringBuilder(); sb.insert(插入位置索引, 要插入的内容); ``` - **索引必须为0**(表示头部) - 可插入任何类型数据(自动转为字符串) --- ### 三、代码示例 ```java StringBuilder sb = new StringBuilder(); sb.append("World"); // 当前内容: "World" // 头部插入 sb.insert(0, "Hello "); System.out.println(sb); // 输出: Hello World // 继续在头部插入数字 sb.insert(0, 123); System.out.println(sb); // 输出: 123Hello World ``` --- ### 四、性能注意 ⚠️ **高频头部插入的隐患** 每次在头部插入都需要移动后续所有字符,时间复杂度为*O(n)*。若需频繁头部操作,建议: 1. 改用`LinkedList<String>` 2. 反向构建字符串,最后调用`reverse()` 3. 使用`StringBuffer`(线程安全版,但速度稍慢) --- ### 五、对比其他操作 | 操作 | 方法 | 时间复杂度 | |------------|----------------|----------| | 尾部追加 | `append()` | O(1) | | 头部插入 | `insert(0, x)` | O(n) | | 中间插入 | `insert(i, x)` | O(n) | --- 通过合理选择数据结构操作方法,可以优化字符串处理效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值