String类与StringBuffer,StringBuilder的区别(每日笔记)

String类与StringBuffer,StringBuilder的区别

今天老师讲到String类,StringBuffer,StringBuilder,容易混淆,做个笔记以便记忆,本人初识java,如有错误或者不足,虚心求各位大神教导

String类

  • 包:java.lang.String

java使用String类创建一个字符串变量,字符串变量属于对象。他并不是基本数据类型,是一个类

特点:

  • String类创建对象后不能修改

    • 源码中的String类
    public final class String implements java.io.Serializable, Comparable<String>, CharSequence 
    
    • 通过源码中课发现String类有final修饰,因此它是不允许被继承。这一点主要是从效率和安全方面考虑,效率上面String类型在开发中使用频繁,final类的方法都是final的,编译时可以内联,大大提高了调用效率,安全上,String是Java提供的核心类,这种类是非常底层的,和操作系统交流频繁,如果这种类可以被继承,重写其中的方法,就有可能往才做系统内部写入具有攻击性的代码

    • String的实例对象是不可改变的,任何想要改变字符串的操作,都会产生一个新的实例对象,影响效率

      • 代码示例
      public static void main(String[] args) {
      
              String str="HelloWorld";
              long start = System.currentTimeMillis();
              for (int i = 0; i < 100000; i++) {
                  str+="a";
              }
              long ending = System.currentTimeMillis();
      
              System.out.println("String类运行100000次运行时长"+(ending-start)+"毫秒");
      
      
      • 运行结果
      String类运行100000次运行时长4057毫秒
      

StringBuffer

  • 包: java.lang

我们了解了String一些特点,发现其中的缺陷,String对象一经申明,便不能修改他的内容修改的只是他的地址,频繁的创建新的对象,影响效率。而StringBuffer对象是可以改变它的内容的

  • 如果修改StringBuffer内容,修改的是同一个对象

     public static void main(String[] args) {
            StringBuffer sb=new StringBuffer("hello ");
            System.out.println(System.identityHashCode(sb)+"\t\t"+sb);
            sb.append("world");
            System.out.println(System.identityHashCode(sb)+"\t\t"+sb);
        }
    

    运行结果

    356573597		hello 
    356573597		hello world
    
    • StringBuffer的内存地址并没有改变。说明修改String内容其实是引用关系的改变。
  • 对比String类我们做同样的测试

    public static void main(String[] args) {
            String str=new String("hello ");
            System.out.println(System.identityHashCode(str));
            str=str+"world";
            System.out.println(System.identityHashCode(str));
        }
    

    运行结果

    356573597
    1735600054
    
    • String字符串的内存地址改变了。说明修改String内容其实是引用关系的改变。其实是开辟了两个新的字符串堆内存,然后将String对象的内存地址改为"Hello world"字符串的地址,而旧的字符串并没有任何改变,也没有任何引用。这样就产生了两块垃圾空间。这两个垃圾空间会被GC回收
  • StringBuffer不能像String那样直接用字符串赋值,所以也不能那样初始化。它需要通过构造方法来初始化,一共有4个构造方法:

    public StringBuffer()
    public StringBuffer(CharSequence seq)
    public StringBuffer(int capacity)
    public StringBuffer(String str)
    
StringBuffer的常用方法
  • append()

    public StringBuffer append(T t)
    //将指定类型的数据追加到StringBuffer对象的末尾:
    
  • insert()

    public StringBuffer insert(int offset,T t)
    //将指定类型的数据插入到StringBuffer序列指定位置
    
  • delete()

    public StringBuffer delete(int start,int end)
    //移除StringBuffer序列中的子字符串,从Start开始,到end-1的字符(注意不是字节,所以一个中文和一个英文都相当于一个字符)
    

StringBuilder类

  • 包:java.lang

StringBuilder是在jdk1.5出现的。StringBuilder拥有和StringBuffer一样的构造方法和方法函数,他们都继承于AbstractStringBuilder,但是它与StringBuffer还是有所不同:

  • 线程安全问题:

    • StringBuffer是线程安全的,它所有的public方法都添加了synchronized修饰,而StringBuilder并没有这么做,其中一个源码举例:

       //StringBuffer的append()方法
       @Override
          public synchronized StringBuffer append(String str) {
              toStringCache = null;
              super.append(str);
              return this;
          }
      //StringBuilder的append()方法
      @Override
          public StringBuilder append(String str) {
              super.append(str);
              return this;
          }
      
  • 缓冲区中的区别 :

    • 先上源码:

      //StringBuffer的toString()方法
      @Override
      public synchronized String toString() {
              if (toStringCache == null) {
                  toStringCache = Arrays.copyOfRange(value, 0, count);
              }
              return new String(toStringCache, true);
          }
       
      //StringBuilder的toString()方法
      @Override
          public String toString() {
              // Create a copy, don't share the array
              return new String(value, 0, count);
          }
      
    • StringBuffer每次toString都会直接使用toStringCache值来构造一个字符串,而StringBuilder则每次都需要复制一次字节数组,再构造一个字符串。

  • 性能上面有所区别

    • StringBuffer是线程安全的,所有方法都是同步的,StringBuilder是没有对方法加锁同步的,所以StringBuilder的性能要远大于StringBuffer

    • 举例

       public static void main(String[] args) {
              StringBuffer sbf = new StringBuffer("HelloWorld");
              long start1 = System.currentTimeMillis();
              for (int i = 0; i < 10000000; i++) {
                  sbf.append("a");
              }
              long ending1 = System.currentTimeMillis();
              System.out.println("StringBuffer类运行10000000次运行时长"+(ending1-start1)+"毫秒");
      
              long start2 = System.currentTimeMillis();
              StringBuilder stb = new StringBuilder("HelloWorld");
              for (int i = 0; i < 10000000; i++) {
                  stb.append("a");
              }
              long ending2 = System.currentTimeMillis();
              System.out.println("StringBuilder类运行10000000次运行时长"+(ending2-start2)+"毫秒");
          }
      

      运行结果

      StringBuffer类运行10000000次运行时长524毫秒
      StringBuilder类运行10000000次运行时长172毫秒
      

总结:

一般情况下,如果没有字符串改变或者少量改变的场景下,我们可以使用String,多次反复修改可以用StringBuffer或StringBuilder。在使用场景为多线程时使用StringBuffer,如果是单线程则使用StringBuilder。

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值