String源码解析

来源:互联网 发布:js判断ip能否ping通 编辑:程序博客网 时间:2024/05/21 11:35

String类的声明和定义

public final class String implements java.io.Serializable, Comparable<String>, CharSequence
  1. final关键字的作用

    • final修饰类:这个类不能被继承
    • final修饰方法:不能被重写
    • final修饰属性:此属性就是一个常量,一旦初始化就不可再被赋值。
  2. 可以从定义看的出String类是不能被继承,是线程安全的,因为它是final类型的。

  3. String类实现了三个接口,分别为java.io.Serializable, Comparable, CharSequence。

String类的属性

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

很多java程序员都知道String值是不可变的,其因由就是该属性造成。String其实就是一个被final关键字修饰的字符数组。关于String值是不可变的疑问,有如下代码:

String str = "abc";str = "cde";

这里str是一个指向字符串”abc”的引用对象,str = “cde”是改变str的引用对象,并没有改变字符串的值。

/** Cache the hash code for the string */private int hash; // Default to 0

由官方注释可以得知,这个属性是用于存放字符串的hash值的,并且其默认值为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];

由于String类实现了Serializable接口,故支持序列化和反序列化。
- Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程。
- 如果要将一个java对象序列化,那么对象的类需要是可序列化的。要让类可序列化,那么这个类需要实现如下两个接口:

- Serializable- Externalizable

- 关于对象的序列化,有以下注意事项:

- 对象的类名、Field(包括基本类型、数组及对其他对象的引用)都会被序列化,对象的static Field,transient Field及方法不会被序列化;- 实现Serializable接口的类,如不想某个Field被序列化,可以使用transient关键字进行修饰;- 保证序列化对象的引用类型Filed的类也是可序列化的,如不可序列化,可以使用transient关键字进行修饰,否则会序列化失败。- 反序列化时必须要有序列化对象的类的class文件;当通过文件网络读取序列化对象的时候,必需按写入的顺序来读取。

String类的方法

  1. String的各个构造方法,各方法具体作用见其方法上的注释。
/** 不含参数的构造函数,虽然这个方法是公开的,但一般没什么用,因为字符串是不可变的。  */public String() {    this.value = "".value;}/** 参数为String类型的构造函数 */public String(String original) {        this.value = original.value;        this.hash = original.hash;}/** 参数为char数组类型的构造函数,使用java.utils包中的Arrays类复制,Arrays.copyOf方法和Arrays.copyOfRange方法,    是将原有的字符数组中的内容逐一的复制到String中的字符数组中 */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);    }/** 参数为byte数组,其作用是从bytes数组中的offset位置开始,将长度为length的字节,以charsetName格式编码,    拷贝到String类的value中,最后一个参数还可以为String类型,Charset类型是1.6版本才开始支持的  */  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);    }/** 调用上一个方法,默认转化整个byte数组 */public String(byte bytes[], String charsetName)            throws UnsupportedEncodingException {        this(bytes, 0, bytes.length, charsetName);    }/** 参数为StringBuffer对象,一般不去使用这个方法,使用StringBuffer的toString方法 */    public String(StringBuffer buffer) {        synchronized(buffer) {            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());        }    }/** 参数为StringBuilder对象,一般不去使用这个方法,使用StringBuilder的toString方法 */ public String(StringBuilder builder) {        this.value = Arrays.copyOf(builder.getValue(), builder.length());    }/** 一个特殊的私有构造方法,区别于String(char[] value)方法,该方法性能更优,但可能引起内存泄漏,在1.7后的版本基本不再使用,    其并非将字符数组逐一复制,而是直接引用传入的字符数组,这个方法构造出来的String和参数传过来的char[] value共享同一个数组。 */String(char[] value, boolean share) {    // assert share : "unshared not supported";    this.value = value;}
  1. String类的常用方法
    • 简单方法,见方法上的注释
//取字符串长度public int length() {        return value.length;    }//字符串判空public boolean isEmpty() {        return value.length == 0;    }//取字符串某个位置的字符    public char charAt(int index) {        if ((index < 0) || (index >= value.length)) {            throw new StringIndexOutOfBoundsException(index);        }        return value[index];    }//在本字符串后添加传入的字符串   public String concat(String str) {    int otherLen = str.length();    //如果被添加的字符串为空,返回对象本身    if (otherLen == 0) {        return this;    }    int len = value.length;    char buf[] = Arrays.copyOf(value, len + otherLen);    str.getChars(buf, len);    return new String(buf, true);}//去空public String trim() {    int len = value.length;    int st = 0;    char[] val = value;    /* avoid getfield opcode */    //找到字符串前段没有空格的位置    while ((st < len) && (val[st] <= ' ')) {        st++;    }    //找到字符串末尾没有空格的位置    while ((st < len) && (val[len - 1] <= ' ')) {        len--;    }    //如果前后都没有出现空格,返回字符串本身    return ((st > 0) || (len < value.length)) ? substring(st, len) : this;}
  • equals方法
public boolean equals(Object anObject) {        //如果引用的是同一个对象,返回真        if (this == anObject) {            return true;        }        //如果传入对象不是String类型,返回假        if (anObject instanceof String) {            String anotherString = (String)anObject;            int n = value.length;            //如果char数组长度不相等,返回假            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;    }
  • compareTo方法
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;        /** 从第一个字符开始到lim处为止,如果存在字符不相等,返回(返回值为对象不相等处字符和被比较对象不相等字符的差值)。        否则,返回两个字符串对象的长度之差 */        while (k < lim) {            char c1 = v1[k];            char c2 = v2[k];            if (c1 != c2) {                return c1 - c2;            }            k++;        }        return len1 - len2;    }
  • hashCode方法
public int hashCode() {        int h = hash;        //如果hash没有被计算过,并且字符串不为空,则进行hashCode计算        if (h == 0 && value.length > 0) {            char val[] = value;            for (int i = 0; i < value.length; i++) {                h = 31 * h + val[i];            }            hash = h;        }        return h;    }

hashCode的实现其实就是使用数学公式:

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

如果计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提高。选择数字31的原因,大概率是它是一个质数而且不会太过大(以至于造成数据溢出的情况)。

  • substring方法
/** 字符串截取方法 */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);    }

这里的String(value, beginIndex, subLen)方法会创建一个新的String并返回,虽然会降低一些效率,但避免了内存泄漏的问题。在1.7版本之前,是使用之前讲到的私有构造方法的。