JAVA基础01-String,StringBuffer和StringBuilder

java 基础中字符串用到最多的就是String,StringBuffer和StringBuilder,这三个也是面试中最常问到的,三者之间的异同,其实实际工作中,我们大致知道使用场景,但是要用理论话的语言去总结,总是比较麻烦。

1.String

1.1继承实现关系

1.2 源码分析

  • 1> final 修饰的类无法被继承
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence
  • 2> String的数据存放在final修饰的char数组中,所以String对象初始化之后值不能改
    private final char value[];
  • 3> String 值比较,总共两种方式,一种是继承了Comparable接口,实现compareTo()方法通过逐个字符串比较;另一种方法是,compareToIgnoreCase() 方法,通过静态成员类,实现Comparator方法,逐个char变大写比较,变小写比较;
    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }
  • 4> 字符串之间的关联,String提供了静态的方法,可以将多个字符串通过delimiter进行拼接;
public static String join(CharSequence delimiter, CharSequence... elements) {}
5>字符串的trim()方法,对字符串双端去空 public String trim() { int len = value.length; int st = 0; char[] val = value; /* avoid getfield opcode */
    while ((st &lt; len) &amp;&amp; (val[st] &lt;= ' ')) {
        st++;
    }
    while ((st &lt; len) &amp;&amp; (val[len - 1] &lt;= ' ')) {
        len--;
    }
    return ((st > 0) || (len &lt; value.length)) ? substring(st, len) : this;
}

2.AbstractStringBuilder

2.1 继承实现关系

2.2源码分析

  • 1>初始长度设置,通过构造方法:数据存储在非fianl的char数组中,通过构造函数传参初始化;
 AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
  • 2>.在append的时候,char[]数组进行扩容,一般是现有值长度的2倍+2
public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);//已有长度+拼接字符串长度 为最小的容量
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {//最小长度大于现有长度时,进行扩容
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));//复制生成新的char[]数组
        }
    }
private int newCapacity(int minCapacity) {
        // overflow-conscious code
       int newCapacity = (value.length << 1) + 2;//容量编程 现有长度的2倍+2
        if (newCapacity - minCapacity < 0) { //扩容后还是小于最小长度时,将最小长度赋值给扩容长度
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

3.StringBuilder

1.源码分析

1>  final修饰的类,不可以继承

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence

2> 默认初始长度为16

public StringBuilder() {
        super(16);
    }
public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
}

3>转成字符串toString()方法是生成新的String对象

 @Override
 public String toString() {
       return new String(value,  0 , count);

4.StringBuffer

1.源码分析

1> final修饰不可继承

public final class StringBuffer

2> toString缓存数据;
  1.通过一个transient修饰的字段toStringCache,进行转字符串存储;
  2.在每个值改变的操作将toStringCache设置为空;
  3.在toString()方法中,如果toStringCache为空,就copy新的char[]数组赋值给toStringCache ;
  4.如果StringBuffer中的数值没变动,调用toString方法的时候,直接调用toStringCache就可以了;

private transient char[] toStringCache;
@Override
public synchronized StringBuffer append(long lng) {
   toStringCache = null;
   super.append(lng);
   return this;
}
@Override
public synchronized String toString() {
   if (toStringCache == null) {
      toStringCache = Arrays.copyOfRange(value, 0, count);
   }
   return new String(toStringCache, true);
}

通过上面的可以知道,如下:
相同点:
  1.都是final类,不可以继承;
  2.内部存取数据的都是char数组;
  3.都实现了CharSequeue,可以对字符串进行相关操作;
不同点:
  1.String 和StringBuilder,StringBuffer的区别:
    - 1. String的值final 数组,赋值后不可改变;StringBuilder,StringBuffer 非final  char数组,初始化后可以改变值;
    - 2. String的字符拼接,每拼接一次,相当于生成一个新的字符串;StringBuilder,StringBuffer通过给内部的char数组扩容,不用生成新的对象,效率更高;
    - 3. char数组初始长度都是16 ;

  • 2.StringBuilder 和 StringBuffer 之间的区别:
    - 1. StringBuffer的所有操作都加synchorinized,因此是线程安全的;
        - 2. StringBuffer的toString方法,有缓存,多次toString效率更高;    
    - 3.StringBuilder 效率更高,但是线程不安全;

常见问题:

  • 1.自己写一个String,或StringBuilder类可以替换原有的JDK的String么?
    答:这个问题其实和String,StringBuilder没关系了,而涉及到的是JVM类加载中,双亲委派模型;
     双亲委派模型,是类加载器接收到当前类的加载请求,并不会直接去加载,而是逐级向父加载器发送请求,当父加载器没有相关的类,当前子加载器才自行加载;
posted @   PerfectLi  阅读(263)  评论(1编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
点击右上角即可分享
微信分享提示