Java源码之String

在String的源码上有这么一段注释:
Strings are constant; their values cannot be changed after they
are created. String buffers support mutable strings.
Because String objects are immutable they can be shared.
字符串是常量,在创建后,它们的值是不能改变的。字符串缓冲区支持可变字符串,因为字符串对象是不变的它们可以共享(即StringBuffer)。
String str = “abc”;等价于:
char data[] = {‘a’, ‘b’, ‘c’};
String str = new String(data);

一、String的定义

//在Java中String类其实就是对字符数组的封装
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    //定义的主要变量:
    /** The value is used for character storage. */
    private final char value[];//常量,在构造器中初始化
    /** Cache the hash code for the string */
    private int hash; // Default to 0
    //默认构造函数,使用此构造函数是不必要的,因为字符串是不可变的。
    public String() {
        this.value = new char[0];
    }
    //新建的字符串是original的副本,如非必要,这个构造函数是不必要的,因为字符串是不可变的。
    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }
    //char数组的值拷贝到当前char数组中,char数组的变化不会影响新建的字符串。
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

    //这里还有几个byte数组转字符串的构造函数没有列出

    //StringBuffer里面的字符串也是已char[] value的形式存储的,只不过StringBuffer是线程安全
    //的,需要加
   public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }
}

二、String的常用方法

1、获取字符串相关信息的操作

//字符串的长度,即char[]的长度
 public int length() {
     return value.length;
 }
 public boolean isEmpty() {
    return value.length == 0;
 }

//返回指定位置的char值
 public char charAt(int index) {
      if ((index < 0) || (index >= value.length)) {
          throw new StringIndexOutOfBoundsException(index);
      }
      return value[index];
  }
  //通过特定的charset把当前字符串转变成char数组
 public byte[] getBytes(String charsetName)
            throws UnsupportedEncodingException {
     if (charsetName == null) throw new NullPointerException();
      return StringCoding.encode(charsetName, value, 0, value.length);
 }

//与特定的对象比较,该对象不为空并且是一个字符串,具有相同的字符序列,则返回true。
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;
  }
//字符串忽略大小写的的比较,首先看两个字符串的引用是否是同一个,如果不是的话就对字符串的char数组进行对比,相等就继续比较,不等先转成大写的char值比较,不然再转车些小的char值比较。
 public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true
                : (anotherString != null)
                && (anotherString.value.length == value.length)
                && regionMatches(true, 0, anotherString, 0, value.length);
 }


//从字符串的char数组的toffset位置开始,与prefix比较,如果个数等于prefix.length()的char值与
//prefix的char值相等,则字符串是从 toffset以prefix为开头的字符串
 public boolean startsWith(String prefix, int toffset) {
        char ta[] = value;
        int to = toffset;
        char pa[] = prefix.value;
        int po = 0;
        int pc = prefix.value.length;
        // Note: toffset might be near -1>>>1.
        if ((toffset < 0) || (toffset > value.length - pc)) {
            return false;
        }
        while (--pc >= 0) {
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        return true;
   }
 public boolean startsWith(String prefix) {
        return startsWith(prefix, 0);
 }
 public boolean endsWith(String suffix) {
        return startsWith(suffix, value.length - suffix.value.length);
 }

//s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
 public int hashCode() {
      int h = hash;
      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;
  }

//返回指定字符的在该字符串中的第一个位置的索引
// ch   a character (Unicode code point)
public int indexOf(int ch) {
   return indexOf(ch, 0);//正序遍历查找
}
//返回指定字符的在该字符串中的最后一个位置的索引
public int lastIndexOf(int ch) {
    return lastIndexOf(ch, value.length - 1);//倒序遍历查找
}


public int indexOf(String str) {
       return indexOf(str, 0);
}

public boolean contains(CharSequence s) {
        return indexOf(s.toString()) > -1;
}

2、字符串的增删改操作

上面的是一些获取信息的基本操作,下面的操作源代码则反映了string的不可变性:

 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);
 }
//将指定的字符串拼接在当前字符串之后,先把当前字符串的char数组copy到新的char数组buf中,在使用
//getChars方法把str的char数组添加到buf中,最后生成一个新的string并返回。
 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 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;
    }

不仅在这几个方法,包括toUpperCase、toLowerCase、trim等方法都是自己本身或者调用的方法先对char数组进行操作,操作完成后生成一个新的String对象并返回。
小结:

1、String引用的的char数组value是一个private final定义的变量,我们没有权限改变这个数组的内容(反射机制是可以操作这个value引用的值的,但是除非脑子有病才会这么做吧),也不能改变这个char数组的引用(final的特性,参考final关键字)。

2、字符串的增删改等改变操作,都是自己本身或者调用的方法先对char数组进行操作,操作完成后生成一个新的String对象并返回。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章