String,StringBuilder和StringBuffer

String,StringBuilder和StringBuffer

一,String

String类的特性
  • public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
        private final char value[];
    
  • String是被final修饰的类,不能被继承。

  • String实现了Serializable和Comparable接口,表示String支持序列化和可以比较大小。

  • String底层是通过char类型的数据实现的,并且被final修饰,所以字符串的值被创建之后就不可以被修改,具有不可变性。

String的实例化方式
  • 通过字面量方式实例化

    • String str = "abc";
      
  • new+构造器的方法实例化

    • String str=new String("abc");
      
  • 区别

    • 通过字面量方式为字符串赋值时,此时字符串存储在堆方法区的字符串常量池中;
    • new+构造器方式实例化字符串时,字符串对象存储在堆中,但是字符串的值仍然存储在方法区的常量池中。
为什么设计String不可变?
  • 因为String使用的过多,如果设计为可变的话,在多线程使用String时,字符串的值可能会因为多线程原因而改变,会引发线程安全问题,所以设计为不可变的。
String真的不可变吗?
  • 其实也是可以变的,使用String.class.getDeclaredField(“value”)可以读取或修改改字段的Field对象。

  • String.class.getDeclaredField(“value”)是一个反射的语句,用于获取String类中的value字段,该字段存储了字符串的字符数组。

    在java中,反射是一种强大的机制,它允许程序在运行时获取并操作类的信息,包括类的字段,方法,构造函数等。通过反射,可以在程序运行时获取类的私有字段或方法,并进行修改或调用。

    需要注意的是,由于字符串对象是不可变的,因此不建议通过反射的方式修改字符串对象中的字符数组。这样可能会导致字符串对象的不一致性,从而引起程序错误。

二,StringBuffer和StringBuilder

​ 它们的底层也是用一个数组来存储字符串的值,并且数组默认长度为16,即一个空的StringBuffer对象长度为16。但是当我们调用有参构造函数创建一个StringBuffer对象时,数组长度就不再时16了,而是根据当前对象的值来决定数组的长度,数组的长度为”当前对象的值的长+16“.所以一个StringBuffer创建完成后,又16个字符的空间可以对其值进行修改。如果修改的值范围超出16个字符,会先检查StringBuffer对象的原char数组的容量能不能装下新的字符串,如果装不下,则会对char数组进行扩容。

StringBuffer
  • 当我们对字符串进行拼接操作时,每次拼接,都会构建一个新String对象,即耗时又浪费时间。而StrignBuffer就可以解决这个问题,是一个线程安全的可变字符序列。
  • 当一个StringBuffer被创建后,通过StringBuffer提供的方法就可以改变这个字符串对象的字符序列,但都不会产生新的对象。
StringBuilder
  • StringBuilder和StringBuffer基本相似,他们的原理和操作一样,两个类的构造器和方法也基本相同。
  • 不同的时:StringBuilder没有实现线程安全功能,但是性能略高。
StringBuffer和StringBuilder常用的方法
  • StringBuffer append(xxx);//拼接字符串
    StringBuffer delete(int start,int end);//删除指定范围的内容,左开右闭
    StringBuffer replace(int start, int end, String str);//替换指定范围的内容
    StringBuffer insert(int offset, xxx);//在指定位置插入指定的内容
    StringBuffer reverse();//把当前字符序列逆转
    public int indexOf(String str);//返回指定子字符串在当前字符串中第一次出现处的索引
    public String substring(int start,int end);//返回指定范围的子字符串
    public int length();//返回字符串的长度
    public char charAt(int n );//获取指定索引处的字符
    public void setCharAt(int n ,char ch);//设置指定索引处的字符
    
StringBufffer和StringBudiler的区别?
  • 线程安全
    • StringBuffer线程安全
    • StringBuilder线程不安全
  • 缓冲区
    • StringBuffer每次获取toString都会直接使用缓存区的toStringCache值来构造一个字符串。
    • StringBuilder则每次都需要复制一次字符数组,再构造一个字符串。
  • 性能
    • StringBuilder没有对方法加锁同步的,所以StringBuilder的性能大于StringBuffer.
    • StringBuilder适合单线程场合,而StringBuffer适用于在多线程操作同一个StringBuffer的场景。
StringBuffer如何实现线程安全?
  • @Overridepublic 
    synchronized int length() {    return count;}
    @Overridepublic 
    synchronized int capacity() {    return value.length;}
    
  • 我们可以看到,StringBuffer类中的方法都添加了synchounized关键字,也就是给这个方法添加了一个锁,用来保证线程安全。

StringBuffer是怎样进行扩容的?
  • 扩容的逻辑就是创建一个新的char数组,将现有的容量扩大一倍在加2,如果还是不够大则直接等于需要的容量大小。扩容完成后,将数组的内容复制到新数组,最后将指针指向新的char数组。
  • 如果原字符数组的长度小于64,那么新的容量是原来的2倍加2。
  • 如果原字符数组的长度大于等于64,那么新的容量是原来的1.5倍。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值