String源码详解

1.今天来解析下常用的String类 , 由于源码太多,就解析几个重要的方法。见下面我自己定义的String类代码:

//final 不可被继承
final class MyString {
	// 真正 存储 字符串的地方 , final 不可变
	private final char value[];
	// 指定 value 的从哪个位置起 算有效字符. 感觉没啥用
	private final int offset;
	// 字符串的长度
	private final int count;
	//为了不每次都计算hash值 , 缓存hash值,见hashCode方法
	private int hash;

	public MyString() {
		this.offset = 0;
		this.count = 0;
		this.value = new char[0];
	}

	MyString(int offset, int count, char value[]) {
		this.value = value;
		this.offset = offset;
		this.count = count;
	}
	// 第一次, 需要计算hash值,然后缓存到全局变量hash上, 后面 就直接拿,增加效率
	public int hashCode() {
		int h = hash;
		if (h == 0) {
			int off = offset;
			char val[] = value;
			int len = count;

			for (int i = 0; i < len; i++) {
				h = 31 * h + val[off++];
			}
			hash = h;
		}
		return h;
	}

	// 字符串长度
	public int length() {
		return count;
	}

	// 字符串是否为空
	public boolean isEmpty() {
		return count == 0;
	}

	// 第几个位置的字符
	public char charAt(int index) {
		return value[index + offset];
	}

	// 循环遍历 真正的char数组 比每个char
	public boolean equals(Object anObject) {
		MyString anotherString = (MyString) anObject;
		int n = count;
		if (n == anotherString.count) {
			char v1[] = value;
			char v2[] = anotherString.value;
			int i = offset;
			int j = anotherString.offset;
			while (n-- != 0) {
				if (v1[i++] != v2[j++])
					return false;
			}
			return true;
		}
		return false;
	}

	// 是否已 prefix开头
	public boolean startsWith(MyString prefix, int toffset) {
		char ta[] = value;
		int to = offset + toffset;// 从哪个位置开始查找
		char pa[] = prefix.value;
		int po = prefix.offset;
		int pc = prefix.count;
		// Note: toffset might be near -1>>>1.
		if ((toffset < 0) || (toffset > count - pc)) {
			return false;
		}
		while (--pc >= 0) { // 直到prefix被遍历完
			// 同位置 时的字符 比较 ,当有一个不同就代表不同了
			if (ta[to++] != pa[po++]) {
				return false;
			}
		}
		return true;
	}

	// 截取 beginIndex 到 endIndex 的字符串 , 若截取的范围是0到自己的长度就返回自己 , 否则返回一个新的字符串
	public MyString substring(int beginIndex, int endIndex) {
		return ((beginIndex == 0) && (endIndex == count)) ? this
				: new MyString(offset + beginIndex, endIndex - beginIndex,
						value);
	}

	// 连接字符串(将str连接到后面), 如果被连接的字符串为空 , 则返回本身, 否则返回一个新的字符串
	public MyString concat(MyString str) {
		int otherLen = str.length();
		if (otherLen == 0) {
			return this;
		}
		// 构造一个可以存放这两个数组 的 字符数组
		char buf[] = new char[count + otherLen];
		// 将 value 拷贝到 buf里面(从buf的0位置开始)
		getChars(0, count, buf, 0);
		// 将 str 的value 拷贝到 buf (从buf 的count位置开始拷贝)
		str.getChars(0, otherLen, buf, count);
		return new MyString(0, count + otherLen, buf);
	}

	public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
		System.arraycopy(value, offset + srcBegin, dst, dstBegin, srcEnd
				- srcBegin);
	}

	// 去除字符串首位的 空格, 如果没有就返回本身,否则返回一个新的字符串
	public MyString trim() {
		int len = count;
		int st = 0;
		int off = offset; /* avoid getfield opcode */
		char[] val = value; /* avoid getfield opcode */
		// 记录从前面开始不是空格的位置。 从val的前面开始找, <= 空格的 ,空格就是32 , 但
		// 为啥要小于32呢?查看ASCII表,最小的就是32
		while ((st < len) && (val[off + st] <= ' ')) {
			st++;
		}
		// 与上面一样 , 只是从末尾开始
		while ((st < len) && (val[off + len - 1] <= ' ')) {
			len--;
		}
		// ((st > 0) || (len < count)) :代表前面或者后面有空格。]
		// substring(st, len) :截取 不是空格的部分
		return ((st > 0) || (len < count)) ? substring(st, len) : this;
	}

	/**
	 * 放入常量池 new String()构造的字符串 调用才有意义 先查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,
	 * 如果没有,则在常量池中增加并返回当前引用。 常量池(constant
	 * pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。 它包括了关于类、方法、接口等中的常量,也包括字符串常量。
	 */
	public native String intern();
}

代码要认真一行一行看到位,就可以看懂,谢谢大家!祝大家元旦快乐!!
老生常谈:深圳有爱好音乐的会打鼓(吉他,键盘,贝斯等)的程序员和其它职业可以一起交流加入我们乐队一起嗨。我的QQ:657455400

强烈推荐一套Java进阶博客,都是干货,走向架构师不是梦!

Java进阶全套博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值