前言
本人使用的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;
}
}