String、StringBuffer和StringBuilder的区别

一、String

1、String不可变类

String是Immutable类的典型实现,被声明为final class,是不可变类,即一旦String对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。除了hash这个属性,其他属性都声明为final;
因为它的不可变性,拼接字符串时会产生很多无用的中间对象,频繁的拼接String字符串会对性能有影响,如

String s = "a";
s = "b";
System.out.println(s);  // 输出结果为b

其实这里存在一个String使用陷阱

string s="a"; //创建了一个字符串 
s="b"; //实际上原来的"a"字符串对象已经丢弃了,现在又产生了一个字符串对象"b"。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。

如图:s对象存储空间图
在这里插入图片描述

2、String类不可变的原理

String类是用final修饰的,表示无法被继承,String的本质是一个char数组,然后用final修饰,不过final限制不了数组内部的数据,所以还用了private修饰,并且没有暴露出set方法,这样外部就接触不到这个属性,所以无法修改。
在这里插入图片描述
当我们需要设计一个不可变类时,就可以参考String类的设计:用final修饰类,private final修饰属性,同时不对外提供set方法。
不可变类的好处就是安全,因为知道这个对象不可能被修改,因此可以放心大胆的使用,在多线程环境下也是线程安全的。

3、String重写equals方法

String类中会重写equals()方法,使得equals()方法比较的是两个对象存放的值,而不是两个对象的内存地址。

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

重写equals方法的同时需要重写hashCode方法。

4、String常量池

String常量池的概念:

在Java中,JVM(Java虚拟机)存在一个特殊的内存空间,用于存放String类型的常量,这个特殊的内存空间被称为“String常量池”;
String常量池用于保存在编译期间就已经确定的一些字符常量,加入了垃圾回收等操作,可以节省空间,提高效率;
当新创建的字符串在常量池中存在时,JVM会直接使用常量池中已存在的字符串的内存地址,而不是重新创建新的内存空间。

5、String str=“abc” 和 String str=new String(“abc”)的区别

5.1、String直接赋值(String str = “abc”;)
  创建一个或不创建对象。如果“abc”在String常量池中不存在,会在String常量池中创建一个String对象(“abc”),然后str指向这个内存地址,无论以后用这种方式创建多少个值为“abc”的字符串对象,始终只有一个内存地址被分配;如果“abc” 在String常量池中存在, str直接指向这个内存地址。

String str1 = "abc";
String str2 = "abc";
String str3 = "abc";
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // true

5.2、使用new String创建字符串(String str = new String(“abc”);)
  会创建一个或两个对象。因为用到new关键字,肯定会在堆中创建一个String对象,如果String常量池中已经存在”abc”,则不会在String常量池中创建一个String对象,如果不存在,则会在String常量池中也创建一个对象。

String str1 = new String("abc");
String str2 = new String("abc");
String str3 = new String("abc");
System.out.println(str1 == str2);//false
System.out.println(str1 == str3);//false

为了提升jvm(JAVA虚拟机)性能和减少内存开销,避免字符的重复创建,项目中还是不要使用new String去创建字符串,最好使用String直接赋值。

6、String拼接字符串

字符串拼接可分为变量拼接和已知字符串拼接。只要拼接内容存在变量,那么该拼接后的新变量就是在堆内存中新建的一个对象实体。

String str = "abc"; 
String str1 = "abcd"; 
String str2 = str+"d"; // 拼接字符串,此时会在堆中新建一个abcd的对象,因为str2编译之前是未知的
String str3 = "abc"+"d"; // 拼接之后str3还是abcd,所以还是会指向字符串常量池的内存地址
System.out.println(str1==str2); // false
System.out.println(str1==str3); // true

二、StringBuffer、StirngBuilder可变字符序列)

StringBuffer/StringBuilder就是为了解决大量拼接字符串时会产生很多中间对象问题而提供的一个类,它提供了append和add方法,可以将字符串加到已有序列的末尾或指定位置。StringBuffer是一个可变的字符串类,我们可以把它看成是一个容器,这里的可变指的是 StringBuffer/StringBuilder对象中的内容是可变的。

StringBuffer s = new StringBuffer("a");
s.append("b");
System.out.println(s); //输出结果为ab

StringBuffer类下s对象的内存空间图
在这里插入图片描述
所以说StringBuffer对象是一个字符序列可变的字符串,它没有重新生成一个对象,而且在原来的对象中可以连接新的字符串

StringBuffer/StringBuilder的区别
事实上,StringBuilder和StringBuffer基本类似,两个类的构造器和方法也基本相同。区别在于StringBuffer执行并发操作,是线程安全的,它把所有修改数据的方法都加上了synchronized,适合多线程中使用;StringBuilder不支持并发操作,线程不安全,但在单线程中StringBuilder的性能比StringBuffer高。
StringBuffer和StringBuilder二者都继承了AbstractStringBuilder,底层都是利用可修改的char数组(JDK9以后时byte数组)

StringBuffer如何实现线程安全
通过在方法中加synchronized关键字,使其成为同步方法
在这里插入图片描述

StringBuilder和StringBuffer使用选择
如果程序是在单线程下运行,或者是不必考虑到线程同步问题,我们应该优先使用StringBuilder类,性能更高,速度更快;如果要保证线程安全,自然是StringBuffer。

什么时候会使用StringBuffer/StringBuilder
存在大量字符串拼接的场景时,需要使用StringBuffer/StringBuilder,如果能预知大小的画最好在new StringBuffer/StringBuilder的时候设置好capacity,避免多次扩容的开销,扩容要抛弃原有数组,还要进行数据拷贝创建新数组,影响性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chenzm666666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值