您的位置:首页 > 编程语言 > Java开发

Java源码之String

2016-04-26 15:47 573 查看
在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&
4000
gt;>>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对象并返回。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码 java