且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

String源码简析(未完成,待本周末更新)

更新时间:2021-12-31 13:31:17

类和接口

String类被定义成public final class,所以String类无法被继承。

String类实现了Serializabel、Comparabe、CharSequence三个接口,分别对应着序列化、排序、字符串处理三个方面的功能。

类属性

String类底层有固定长度的字符数组组成,用hash的方法缓存字符串,含有一个序列化ID以及一个用于序列化的ObjectStreamField类,这个类我们会单独拿出一篇文章来讲。

private final char value[];
private int hash;
private static final long seriaVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
            new ObjectStreamField[0];


类方法

构造方法

String构造数据的构造方法有很多实现方法。

默认构造方法

public String();

新建一个单个字符的char数组。常见于String str = new String();

带参构造方法

public String(String original);

String类型的传参直接赋值

public String(char value[]);

char数组则使用Arrays来直接拷贝,当然,可以在传参的时候,可以再加上位移量和长度(数量),详见String的源码

public String(int[] codePoint, int offset, int count);
public String(byte ascii[], int hibyte, int offset, int count);
public String(byte bytes[], Charset charset);
public String(byte bytes[], int offset, int length);
public String(byte bytes[]);

一些byte及编码类型的传参不再赘述。

public String(StringBuffer buffer);
public String(StringBuilder builder);

JDK1.5之后,String可以通过StringBuffer和StringBuilder调用Arrays.copyOf()来初始化String。其中,StringBuffer在调用的时候,会加锁以保证线程安全。

一般方法

字符操作length()isEmpty()charAt()codePointAt()codePointBefore()codePointCount()getBytes() 方法功能同名。

public boolean equals(Object anObject);
public boolean equalsIgnoreCase(String anotherString); // 大小写不敏感
  • String是final对象,所以在写equals方法时,是在比较String的各位char数值。
  • String是不可变对象,所以该方法没有涉及线程相关的设计。
public boolean contentEquals(StringBuffer sb);
public boolean contentEquals(CharSequence cs);
  • equals()方法只能比较String,而contentEquals的比较类型更多
  • contentEquals针对StringBuffer、StringBuilder、String、Charsequence有着不同的比较方法。
  • StringBuffer多加了一个synchronnized来保证线程安全。
  • contentEquals功能同名,只比较内容,而忽略类型。
public int compareTo(String anotherString);

按字典序列比较内容,返回不同字符处的距离或不同字符串长度,相等返回0

内部类 CaseInsensitiveComparator

我们发现内部类CaseInsensitiveComparator的compare比较方法为了实现大小写不敏感,把字符分别toUppperCasetoLowerCase比较了一遍,

一般方法

public boolean regionMatches(int toffset, String other, int ooffset,int len);
public boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len);

比较两个字符串从某处开始的特定长度的字串是否相等。

public String concat(String str);

concact是拼接函数,其中为了设计char数组的拷贝,使用了传入String对象的getChars()方法。

void getChars(char dst[], int dstBegin) {
    System.arraycopy(value, 0, dst, dstBegin, value.length);
}

在这个函数中,使用了System的arraycopy方法,把当前字符串拷贝到传入字符串数组的结尾。

最后,concat返回一个新的String对象

public String replace(char oldChar, char newChar) {
    if (oldChar != newChar) {
        int len = value.length;
        int i = -1;
        char[] val = value; /* avoid getfield opcode */

        while (++i < len) {
            if (val[i] == oldChar) {
                break;
            }
        }
        if (i < len) {
            char buf[] = new char[len];
            for (int j = 0; j < i; j++) {
                buf[j] = val[j];
            }
            while (i < len) {
                char c = val[i];
                buf[i] = (c == oldChar) ? newChar : c;
                i++;
            }
            return new String(buf, true);
        }
    }
    return this;
}

replace方法用于返回一个替换字符串,但是这个方法重复执行了部分的循环操作。第一个循环用于找到第一个匹配的字符的位置,之后,再从头到此位置进行替换,最后从该位置之后再判断。这样做的目的是什么呢?

  • Java是高地址存低位,低地址存高