【Java字符串】String、StringBuilder和StringBuffer

前言

本人使用的jdk8。

String

String是Java中最常用的类,这个类并不是Java基础类型,它的底层是char数组实现的,然后提供了众多操作这个char数组的方法。String类是final的,即不能被继承的,String中的字符串也是不可变的。

1. 底层实现

下面是String类的一点注释介绍:所有的字符串字面量(string literals)如“abc”,都被实现成了String类的实例。字符串就是常量,在被创建后,它们的值不能改变。

字符串字面量都是在类加载的时候,调用String对象的intern方法,将String对象加载到运行是常量池和字符串常量池中,详情参考:https://blog.csdn.net/qq_34039868/article/details/103957965

char数组value是String对象的实际保存值的地方,该属性是private final的,不能直接通过String对象访问该属性,必须通过内部的方法来操作该数组。从语法上来说,可以在内部方法中对value中的元素进行修改(不能修改value引用指向的地址,这意味着一旦对value赋值,数组的长度不能再改变),但String类内部所有的操作都没有直接修改value中的元素,而是将结果保存在了一个新new的String对象中,如下面的substring方法。因此说String对象是不可变的。

 /* The {@code String} class represents character strings. All
 * string literals in Java programs, such as {@code "abc"}, are
 * implemented as instances of this class.
 * <p>
 * Strings are constant; their values cannot be changed after they
 * are created.
 */ 
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {

 /** The value is used for character storage. */
    private final char value[];

    public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }
    
    ......
}

2. 常用方法

  • 判断功能

boolean equals(Object obj):比较字符串的内容是否相同,区分大小写

boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写

boolean contains(String str):判断大字符串中是否包含小字符串

boolean startsWith(String str):判断字符串是否以某个指定的字符串开头

boolean endsWith(String str):判断字符串是否以某个指定的字符串结尾

boolean isEmpty():判断字符串是否为空。

  • 获取功能

int length():获取字符串的长度。

char charAt(int index):获取指定索引位置的字符

int indexOf(int ch):返回指定字符(ASCII码或字符都行)在此字符串中第一次出现处的索引。

int indexOf(String str):返回指定字符串在此字符串中第一次出现处的索引。

int indexOf(int ch,int fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引。

int indexOf(String str,int fromIndex):返回指定字符串在此字符串中从指定位置后第一次出现处的索引。

lastIndexOf

String substring(int start):从指定位置开始截取字符串,默认到末尾。

String substring(int start,int end):从指定位置开始到指定位置结束截取字符串。

  • 转换功能

byte[] getBytes():把字符串转换为字节数组。

char[] toCharArray():把字符串转换为字符数组。

static String valueOf(char[] chs):把字符数组转成字符串。

static String valueOf(int i):把int类型的数据转成字符串。

 

注意:String类的valueOf方法可以把任意类型的数据转成字符串。

String toLowerCase():把字符串转成小写。

String toUpperCase():把字符串转成大写。

String concat(String str):把字符串拼接。

  • 替换功能

String replace(char old,char new)

String replace(String old,String new)

  • 去除字符串两空格

String trim()

  • 按字典顺序比较两个字符串

int compareTo(String str)

int compareToIgnoreCase(String str)

 

AbstractStringBuilder

该类是StringBuilder和StringBuffer的父类,StringBuilder和StringBuffer的底层实现代码就在AbstractStringBuilder中

1. 底层实现

AbstractStringBuilder是一个可变的字符序列,属性value是存储字符串的数组,count是value中已存在字符的数量(count不一定等于value.length)。具体的属性方法见下面代码:

/**
 * A mutable sequence of characters.
*/
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    // 字符串容器
    char[] value;

    // value中已添加字符的个数
    int count;

    // value的最大长度
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    AbstractStringBuilder() {}

    // 构造指定容量的char数组
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

   // 返回value中字符的个数
   public int length() {    return count;    }

   // 返回value的容量
   public int capacity() {    return value.length;    }
}

2. 具体方法

2.1 append()和insert()

AbstractStringBuilder提供操作value的方法主要有两个:append()和insert()。并且提供了很多重载方法,能传入的参数包括基础类型和String等,下面只列出了参数为String的重载方法。StringBuilder和StringBuffer中的append()和insert()都是调用AbstractStringBuilder的append()和insert()。方法操作很简单,唯一复杂地方在于扩容方法ensureCapacityInternal()。

    // 添加指定字符串到value中,添加到已存在字符的后面
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);    // 判断是否需要扩容,是则扩容
        str.getChars(0, len, value, count);     // 将str中的字符复制到指定字符数组中
        count += len;
        return this;
    }

    // 将str插入到value的offset处
    public AbstractStringBuilder insert(int offset, String str) {
        if ((offset < 0) || (offset > length()))
            throw new StringIndexOutOfBoundsException(offset);
        if (str == null)
            str = "null";
        int len = str.length();
        ensureCapacityInternal(count + len);
        System.arraycopy(value, offset, value, offset + len, count - offset);
        str.getChars(value, offset);
        count += len;
        return this;
    }

2.2 ensureCapacityInternal

该方法确保添加的str能够被value容纳,若value空间不够,则会进行扩容。默认扩容长度是newCapacity = value.length * 2 + 2;若默认扩容长度不够,则取str.length + count;若str.length + count为负数或者大于Integer.MAX_VALUE则会抛出OutOfMemoryError。从下面代码可知:str的长度最大可以取到Integer.MAX_VALUE,并不受到字段MAX_ARRAY_SIZE的限制,这里要注意一下。

    // 判断扩容的主方法
    private void ensureCapacityInternal(int minimumCapacity) {
        // 若需要扩容,执行大括号内代码
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

    // 计算扩容后的value的长度并返回,默认长度是value.length * 2 + 2。若最终minCapacity小于0 
    // 或者比Integer.MAX_VALUE大则会抛出OutOfMemoryError。
    private int newCapacity(int minCapacity) {
        int newCapacity = (value.length << 1) + 2; // 默认长度
        if (newCapacity - minCapacity < 0) {       // 若默认长度还不能满足需求,取minCapacity
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

    // 获取最大长度,若minCapacity比MAX_ARRAY_SIZE大则返回minCapacity,否则返回                    
    // MAX_ARRAY_SIZE
    private int hugeCapacity(int minCapacity) {
        if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE)
            ? minCapacity : MAX_ARRAY_SIZE;
    }

   

 

StringBuilder

由StringBuilder的注释可知,StringBuilder是一个非线程安全的可变类,它继承了AbstractStringBuilder。这个类是为了在单线程情况下替代StringBuffer而设计的。相对于StringBuffer,更推荐使用StringBuilder,因为StringBuilder在绝大部分情况下效率更高。

空参new一个StringBuilder,value的长度为16。通过下面代码得知,StringBuilder的append和insert方法就是调用的父类AbstractStringBuilder的append方法。

/**
 * A mutable sequence of characters.  This class provides an API compatible
 * with {@code StringBuffer}, but with no guarantee of synchronization.
 * This class is designed for use as a drop-in replacement for
 * {@code StringBuffer} in places where the string buffer was being
 * used by a single thread (as is generally the case).   Where possible,
 * it is recommended that this class be used in preference to
 * {@code StringBuffer} as it will be faster under most implementations.
*/
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
    public StringBuilder() {    super(16);    }        // 默认长度为16

    public StringBuilder(int capacity) {    super(capacity);    }

    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

    @Override
    public StringBuilder insert(int offset, String str) {
        super.insert(offset, str);
        return this;
    }
}

 

StringBuffer

StringBuffer与StringBuilder唯一的区别就是它是线程安全的,因为所有的方法上都加了synchronized关键字,使得一个线程在操作value时其它线程必须等待,缺点是效率会比StringBuilder低。

// A thread-safe, mutable sequence of characters.
 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    public StringBuffer() {    super(16);    }

    public StringBuffer(int capacity) {    super(capacity);    }

    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

    @Override
    public synchronized StringBuffer insert(int offset, String str) {
        toStringCache = null;
        super.insert(offset, str);
        return this;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值