JDK源码之String

1、String类简介

String类是日常开发中很常用,该类用关键字final修饰,说明String类不能够被继承,里面的方法不能被重写,String是不可变的。String类实现了Comparable<String>和CharSequence

接口,提供了字符串比较、获取字符串长度等方法。

2、源码

2.1、String类的属性

复制代码
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** 存储字符串的字符数组*/
    private final char value[];

    /** Cache the hash code for the string */
  //用于存放字符串的hashCode码,第一次调用hashCode()函数的时候计算并缓存起来,之后再调用hashCode()函数时直接冲缓存中获取,不用再次计算
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

    /**
     * Class String is special cased within the Serialization Stream Protocol.
     *
     * A String instance is written into an ObjectOutputStream according to
     * <a href="{@docRoot}/../platform/serialization/spec/output.html">
     * Object Serialization Specification, Section 6.2, "Stream Elements"</a>
     */

  /用于自定义序列化
    private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];
}

2.2、String类构造方法

复制代码
public String() {
        this.value = "".value;
    }

public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= value.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

public String(int[] codePoints, int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= codePoints.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > codePoints.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }

        final int end = offset + count;

        // Pass 1: Compute precise size of char[]
        int n = count;
        for (int i = offset; i < end; i++) {
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))
                continue;
            else if (Character.isValidCodePoint(c))
                n++;
            else throw new IllegalArgumentException(Integer.toString(c));
        }

        // Pass 2: Allocate and fill in char[]
        final char[] v = new char[n];

        for (int i = offset, j = 0; i < end; i++, j++) {
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))
                v[j] = (char)c;
            else
                Character.toSurrogates(c, v, j++);
        }

        this.value = v;
    }

@Deprecated
    public String(byte ascii[], int hibyte, int offset, int count) {
        checkBounds(ascii, offset, count);
        char value[] = new char[count];

        if (hibyte == 0) {
            for (int i = count; i-- > 0;) {
                value[i] = (char)(ascii[i + offset] & 0xff);
            }
        } else {
            hibyte <<= 8;
            for (int i = count; i-- > 0;) {
                value[i] = (char)(hibyte | (ascii[i + offset] & 0xff));
            }
        }
        this.value = value;
    }

@Deprecated
    public String(byte ascii[], int hibyte) {
        this(ascii, hibyte, 0, ascii.length);
    }

public String(byte bytes[], int offset, int length, String charsetName)
            throws UnsupportedEncodingException {
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(charsetName, bytes, offset, length);
    }

public String(byte bytes[], int offset, int length, Charset charset) {
        if (charset == null)
            throw new NullPointerException("charset");
        checkBounds(bytes, offset, length);
        this.value =  StringCoding.decode(charset, bytes, offset, length);
    }

public String(byte bytes[], String charsetName)
            throws UnsupportedEncodingException {
        this(bytes, 0, bytes.length, charsetName);
    }

public String(byte bytes[], Charset charset) {
        this(bytes, 0, bytes.length, charset);
    }

public String(byte bytes[], int offset, int length) {
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(bytes, offset, length);
    }

public String(byte bytes[]) {
        this(bytes, 0, bytes.length);
    }

public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }

public String(StringBuilder builder) {
        this.value = Arrays.copyOf(builder.getValue(), builder.length());
    }

String(char[] value, boolean share) {
        // assert share : "unshared not supported";
        this.value = value;
    }

2.3、String类常用方法

  • 判断字符串是否为空
复制代码
public boolean isEmpty() {
     //根据字符串数组的长度判断char value[]的长度
        return value.length == 0;
    }
  • 获取字符串的长度
复制代码
public int length() {
     //返回char value[]的长度
     return value.length; 
复制代码
  }
  • 获取特定位数的字符
复制代码
public char charAt(int index) {
     //检查传入的位置是否小于0或者大于数组长度
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
     //返回传入位置的字符
        return value[index];
    }
复制代码
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
  • 复制字符串到目标数组中,从destBegin开始
复制代码
void getChars(char dst[], int dstBegin) {
        System.arraycopy(value, 0, dst, dstBegin, value.length);
    }
  • 获取字符串的字节数组,可指定字符集或者不指定字符集
复制代码
public byte[] getBytes(String charsetName)
            throws UnsupportedEncodingException {
        if (charsetName == null) throw new NullPointerException();
        return StringCoding.encode(charsetName, value, 0, value.length);
    }

public byte[] getBytes(Charset charset) {
        if (charset == null) throw new NullPointerException();
        return StringCoding.encode(charset, value, 0, value.length);
    }

public byte[] getBytes() {
        return StringCoding.encode(value, 0, value.length);
    }
  • 忽略大小写的equals
复制代码
public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true
                : (anotherString != null)
                && (anotherString.value.length == value.length)
          //带偏移量的忽略大小写的equals
                && regionMatches(true, 0, anotherString, 0, value.length);
    }
  • 带偏移量的忽略大小写的equals
    • ignoreCase:是否忽略大小写 true-忽略  fale-不忽略
    • toffset:当前字符串的偏移量
    • other:需要比较的字符串
    • ooffset:需要比较的字符串的偏移量
    • len:需要比较的字符长度
复制代码
public boolean regionMatches(boolean ignoreCase, int toffset,
            String other, int ooffset, int len) {
        char ta[] = value;
        int to = toffset;
        char pa[] = other.value;
        int po = ooffset;
        // Note: toffset, ooffset, or len might be near -1>>>1.
        if ((ooffset < 0) || (toffset < 0)
                || (toffset > (long)value.length - len)
                || (ooffset > (long)other.value.length - len)) {
            return false;
        }
        while (len-- > 0) {
            char c1 = ta[to++];
            char c2 = pa[po++];
            if (c1 == c2) {
                continue;
            }
            if (ignoreCase) {
                // If characters don't match but case may be ignored,
                // try converting both characters to uppercase.
                // If the results match, then the comparison scan should
                // continue.
                char u1 = Character.toUpperCase(c1);
                char u2 = Character.toUpperCase(c2);
                if (u1 == u2) {
                    continue;
                }
                // Unfortunately, conversion to uppercase does not work properly
                // for the Georgian alphabet, which has strange rules about case
                // conversion.  So we need to make one last check before
                // exiting.
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                    continue;
                }
            }
            return false;
        }
        return true;
    }
  • 字符串截取
    • beginIndex : 起始位置
    • endIndex:结束位置
复制代码
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);
    }

public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
  • 字符串比较
复制代码
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;
    }
相关推荐
Dolphin_海豚1 天前
vapor 语法糖是如何被解析的
前端·源码·vapor
回家路上绕了弯3 天前
Redis 分布式锁源码深度解析:从原理到实现细节
redis·源码
袋鱼不重5 天前
手把手搭建Vue轮子从0到1:5. Ref 模块的实现
前端·vue.js·源码
plusone5 天前
【React18源码解析】(三)调度
react.js·前端框架·源码
sophie旭6 天前
《深入浅出react》总结之 10.7 scheduler 异步调度原理
前端·react.js·源码
袋鱼不重8 天前
手把手搭建Vue轮子从0到1:4. Reactivity 模块的实现
前端·vue.js·源码
aze9 天前
带你30分钟弄明白useContext的原理,教不会你随便喷!
前端·源码
工业互联网专业10 天前
基于JavaWeb的兼职发布平台的设计与实现
java·vue.js·spring boot·毕业设计·源码·课程设计·兼职发布平台
小七mod11 天前
【Spring】Spring Boot启动过程源码解析
java·spring boot·spring·面试·ssm·源码