学习笔记之String源码
2016-09-24 11:45
162 查看
1.首先如何查看jdk源码:http://jingyan.baidu.com/article/f54ae2fc391cd91e92b849fc.html
2.然后建一个String的对象,按住ctrl,鼠标左键点击String。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
从上面可以看出:
1.String是final的----类上的final表示该类不能被继承。
2.String实现了Serializable,Comparable,CharSequence三个接口。
Serializable:表示对象能被序列化。
Comparable:该接口里面有public int compareTo(T o);方法,此接口强行对实现它的每个类的对象进行整体排序。此排序被称为该类的自然排序 ,类的
compareTo 方法被称为它的自然比较方法 。实现此接口的对象列表(和数组)可以通过 Collections.sort
(和 Arrays.sort )进行自动排序。实现此接口的对象可以用作有序映射表中的键或有序集合中的元素,无需指定比较器。
CharSequence:该接口是字符序列基本接口,里面定义了一些字符序列的基本操作。
3.我们再看下面其实String中储存的字符串是以一个不可变的char数组储存的。(final在字段上表示该字段在第一次赋值之后将不可改变)
<pre name="code" class="java"> /** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
4.String有很多个构造器,就挑了个最简单的构造器进行讲解
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}将String.value就是传入的original的char value[]数组。
这里其实是有点疑问的,如果有看到的高手请帮我解答下不胜感激。这里传入的一个String对象将他的值赋值给了新的String对象,value明明是私有的却可以用.的方式取出来:
目前猜测的理解是因为私有属性是对本类可见的,因为String original是在本类的类型信息中调用,所以是可以访问私有属性的。以下是自己测试的一个例子。
public class A {
private String name;
public String getAName(A a){
return a.name;
}
}能正常编译通过。上述只是猜测,也百度不到这个问题,所以如果有看见的并懂的这块的朋友请留言。
5.接下来就讲一些比较常用的方法。
length();
String是没有length属性的,只有length方法,返回的就是value[]的length属性。
/**
* Returns the length of this string.
* The length is equal to the number of <a href="Character.html#unicode">Unicode
* code units</a> in the string.
*
* @return the length of the sequence of characters represented by this
* object.
*/
public int length() {
return value.length;
}
isEmpty()
判断value.length的值是否为0
public boolean isEmpty() {
return value.length == 0;
}
charAt(int index)
先检测传入的索引号是否越界,如果越界则抛出下标越界异常,不然就取出value[index]。
codePointAt(int index);
逻辑和上述一样,只是这个方法返回的是指定下标的Unicode代码点,
public int codePointAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointAtImpl(value, index, value.length);
}
至于方法Character.codePointAtImpl(value, index, value.length)是Character的关于Unicode的操作,详情可能要参考Unicode简介去了解一些Unicode的知识。
static int codePointAtImpl(char[] a, int index, int limit) {
char c1 = a[index];
if (isHighSurrogate(c1) && ++index < limit) {
char c2 = a[index];
if (isLowSurrogate(c2)) {
return toCodePoint(c1, c2);
}
}
return c1;
}equals(Object anObject);
重写的equals方法。
1.自反性if(this==anObject)return true;
2.类型判断if (anObject instanceof String)
3.if (n == anotherString.value.length)长度判断
4. 再判断每1个字符是否相等。(因为此处操作步骤比较多,先用前面3种做一个范围缩小
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
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;
}
compareTo(String anotherString);
实现Comparable<String>接口要复写的方法,完成自然排序。
先取出长度较小的value长度,然后再这长度中进行2个数组的同时遍历,根据从前到后的char字符的大小比较而得出
* Compares two strings lexicographically.
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;
}
indexOf(String str);
-----》indexOf(str, 0)
----》indexOf(String str, int fromIndex)
-----》indexOf(value, 0, value.length, str.value, 0, str.value.length, fromIndex);
------》indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)
最后会被转换成调用indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)方法。
1.先判断其实坐标是否大于等于数组长度,targetCount == 0 ? sourceCount : -1,若目标数组不为空则找不到返回-1,等于及返回长度就是源字符串的长度。
2. 先将开始index小于0的置为0,然后若查询的是空字符串,直接返回开始查找的index.----即返回fromIndex
3. char first = target[targetOffset];------要查询字符串的起始,直接调用index这为0。
int max = sourceOffset + (sourceCount - targetCount);------最大查到哪个下标,开始查询的下标+源数组的长度-目标数组的长度。
if (source[i] != first) {
while (++i <= max && source[i] != first);
}----若第一个字符串不相等,直接i++往下找,一直找到第1个字符串匹配上
if (i <= max) {--------如果匹配上的坐标到最后还有目标数组长度的容量就进去比较,不然就返回-1.
int j = i + 1;
int end = j + targetCount - 1;
for (int k = targetOffset + 1; j < end && source[j]
== target[k]; j++, k++)
//一直遍历,若source[j] == target[k],且j==end就返回i-sourceOffset,找到目标数组的最开始的下坐标,若source[j] =!= target[k],就进入到i+1下一次循环中
if (j == end) {
/* Found whole string. */
return i - sourceOffset;
}
}
/**
* Code shared by String and StringBuffer to do searches. The
* source is the character array being searched, and the target
* is the string being searched for.
*
* @param source the characters being searched.
* @param sourceOffset offset of the source string.
* @param sourceCount count of the source string.
* @param target the characters being
a184
searched for.
* @param targetOffset offset of the target string.
* @param targetCount count of the target string.
* @param fromIndex the index to begin searching from.
*/
static int indexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
if (fromIndex >= sourceCount) {
return (targetCount == 0 ? sourceCount : -1);
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (targetCount == 0) {
return fromIndex;
}
char first = target[targetOffset];
int max = sourceOffset + (sourceCount - targetCount);
for (int i = sourceOffset + fromIndex; i <= max; i++) {
/* Look for first character. */
if (source[i] != first) {
while (++i <= max && source[i] != first);
}
/* Found first character, now look at the rest of v2 */
if (i <= max) {
int j = i + 1;
int end = j + targetCount - 1;
for (int k = targetOffset + 1; j < end && source[j]
== target[k]; j++, k++);
if (j == end) {
/* Found whole string. */
return i - sourceOffset;
}
}
}
return -1;
}
replace(char oldChar, char newChar)
1.先判断要替换的字符串和老的字符串是否一样,一样的话就直接返回原对象。
2.while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
找到oldChar的坐标。
3. 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++;
}
用新字符替换老字符
4.返回一个new String(buf, true);
* Returns a string resulting from replacing all occurrences of
* {@code oldChar} in this string with {@code newChar}.
*
* @param oldChar the old character.
* @param newChar the new character.
* @return a string derived from this string by replacing every
* occurrence of {@code oldChar} with {@code newChar}.
*/
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;
}
大致就讲解以上几个方法,只是简单的从逻辑角度去分析了一些方法的实现方式和特性,因为是初学,只能先看其形,观其貌。。对其中的设计思路以及思想,和深入的特性理解并没有做过多的解析,因为这可能需要一定的积累,如果有什么建议可以在下面留言~。
欢迎大家发表自己的想法,或者有更深入的见解也可以教教我~
2.然后建一个String的对象,按住ctrl,鼠标左键点击String。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
从上面可以看出:
1.String是final的----类上的final表示该类不能被继承。
2.String实现了Serializable,Comparable,CharSequence三个接口。
Serializable:表示对象能被序列化。
Comparable:该接口里面有public int compareTo(T o);方法,此接口强行对实现它的每个类的对象进行整体排序。此排序被称为该类的自然排序 ,类的
compareTo 方法被称为它的自然比较方法 。实现此接口的对象列表(和数组)可以通过 Collections.sort
(和 Arrays.sort )进行自动排序。实现此接口的对象可以用作有序映射表中的键或有序集合中的元素,无需指定比较器。
CharSequence:该接口是字符序列基本接口,里面定义了一些字符序列的基本操作。
3.我们再看下面其实String中储存的字符串是以一个不可变的char数组储存的。(final在字段上表示该字段在第一次赋值之后将不可改变)
<pre name="code" class="java"> /** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
4.String有很多个构造器,就挑了个最简单的构造器进行讲解
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}将String.value就是传入的original的char value[]数组。
这里其实是有点疑问的,如果有看到的高手请帮我解答下不胜感激。这里传入的一个String对象将他的值赋值给了新的String对象,value明明是私有的却可以用.的方式取出来:
目前猜测的理解是因为私有属性是对本类可见的,因为String original是在本类的类型信息中调用,所以是可以访问私有属性的。以下是自己测试的一个例子。
public class A {
private String name;
public String getAName(A a){
return a.name;
}
}能正常编译通过。上述只是猜测,也百度不到这个问题,所以如果有看见的并懂的这块的朋友请留言。
5.接下来就讲一些比较常用的方法。
length();
String是没有length属性的,只有length方法,返回的就是value[]的length属性。
/**
* Returns the length of this string.
* The length is equal to the number of <a href="Character.html#unicode">Unicode
* code units</a> in the string.
*
* @return the length of the sequence of characters represented by this
* object.
*/
public int length() {
return value.length;
}
isEmpty()
判断value.length的值是否为0
public boolean isEmpty() {
return value.length == 0;
}
charAt(int index)
先检测传入的索引号是否越界,如果越界则抛出下标越界异常,不然就取出value[index]。
codePointAt(int index);
public char charAt(int index) { if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return value[index]; }
逻辑和上述一样,只是这个方法返回的是指定下标的Unicode代码点,
public int codePointAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointAtImpl(value, index, value.length);
}
至于方法Character.codePointAtImpl(value, index, value.length)是Character的关于Unicode的操作,详情可能要参考Unicode简介去了解一些Unicode的知识。
static int codePointAtImpl(char[] a, int index, int limit) {
char c1 = a[index];
if (isHighSurrogate(c1) && ++index < limit) {
char c2 = a[index];
if (isLowSurrogate(c2)) {
return toCodePoint(c1, c2);
}
}
return c1;
}equals(Object anObject);
重写的equals方法。
1.自反性if(this==anObject)return true;
2.类型判断if (anObject instanceof String)
3.if (n == anotherString.value.length)长度判断
4. 再判断每1个字符是否相等。(因为此处操作步骤比较多,先用前面3种做一个范围缩小
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
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;
}
compareTo(String anotherString);
实现Comparable<String>接口要复写的方法,完成自然排序。
先取出长度较小的value长度,然后再这长度中进行2个数组的同时遍历,根据从前到后的char字符的大小比较而得出
* Compares two strings lexicographically.
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;
}
indexOf(String str);
-----》indexOf(str, 0)
----》indexOf(String str, int fromIndex)
-----》indexOf(value, 0, value.length, str.value, 0, str.value.length, fromIndex);
------》indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)
最后会被转换成调用indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)方法。
1.先判断其实坐标是否大于等于数组长度,targetCount == 0 ? sourceCount : -1,若目标数组不为空则找不到返回-1,等于及返回长度就是源字符串的长度。
2. 先将开始index小于0的置为0,然后若查询的是空字符串,直接返回开始查找的index.----即返回fromIndex
3. char first = target[targetOffset];------要查询字符串的起始,直接调用index这为0。
int max = sourceOffset + (sourceCount - targetCount);------最大查到哪个下标,开始查询的下标+源数组的长度-目标数组的长度。
if (source[i] != first) {
while (++i <= max && source[i] != first);
}----若第一个字符串不相等,直接i++往下找,一直找到第1个字符串匹配上
if (i <= max) {--------如果匹配上的坐标到最后还有目标数组长度的容量就进去比较,不然就返回-1.
int j = i + 1;
int end = j + targetCount - 1;
for (int k = targetOffset + 1; j < end && source[j]
== target[k]; j++, k++)
//一直遍历,若source[j] == target[k],且j==end就返回i-sourceOffset,找到目标数组的最开始的下坐标,若source[j] =!= target[k],就进入到i+1下一次循环中
if (j == end) {
/* Found whole string. */
return i - sourceOffset;
}
}
/**
* Code shared by String and StringBuffer to do searches. The
* source is the character array being searched, and the target
* is the string being searched for.
*
* @param source the characters being searched.
* @param sourceOffset offset of the source string.
* @param sourceCount count of the source string.
* @param target the characters being
a184
searched for.
* @param targetOffset offset of the target string.
* @param targetCount count of the target string.
* @param fromIndex the index to begin searching from.
*/
static int indexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
if (fromIndex >= sourceCount) {
return (targetCount == 0 ? sourceCount : -1);
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (targetCount == 0) {
return fromIndex;
}
char first = target[targetOffset];
int max = sourceOffset + (sourceCount - targetCount);
for (int i = sourceOffset + fromIndex; i <= max; i++) {
/* Look for first character. */
if (source[i] != first) {
while (++i <= max && source[i] != first);
}
/* Found first character, now look at the rest of v2 */
if (i <= max) {
int j = i + 1;
int end = j + targetCount - 1;
for (int k = targetOffset + 1; j < end && source[j]
== target[k]; j++, k++);
if (j == end) {
/* Found whole string. */
return i - sourceOffset;
}
}
}
return -1;
}
replace(char oldChar, char newChar)
1.先判断要替换的字符串和老的字符串是否一样,一样的话就直接返回原对象。
2.while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
找到oldChar的坐标。
3. 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++;
}
用新字符替换老字符
4.返回一个new String(buf, true);
* Returns a string resulting from replacing all occurrences of
* {@code oldChar} in this string with {@code newChar}.
*
* @param oldChar the old character.
* @param newChar the new character.
* @return a string derived from this string by replacing every
* occurrence of {@code oldChar} with {@code newChar}.
*/
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;
}
大致就讲解以上几个方法,只是简单的从逻辑角度去分析了一些方法的实现方式和特性,因为是初学,只能先看其形,观其貌。。对其中的设计思路以及思想,和深入的特性理解并没有做过多的解析,因为这可能需要一定的积累,如果有什么建议可以在下面留言~。
欢迎大家发表自己的想法,或者有更深入的见解也可以教教我~
相关文章推荐
- java学习笔记-String源码分析(2)
- 3/23学习String源码笔记记录
- JDK源码学习笔记——String
- Irrlicht 源码学习笔记 【irrstring.h】
- C++ Standard Stl -- SGI STL源码学习笔记(08) string
- java String 源码阅读笔记以及Unicode的学习
- String源码学习笔记
- C#学习笔记之二(stack, queue, string, HashTable,StringBui
- shell脚本学习笔记(三)mysql与ARP表的绑定源码
- Python学习笔记二(String字符串操作)
- 学习笔记:解读CppUnit源码7
- spring学习笔记:Spring IOC容器,Spring源码
- spring学习笔记之DispatcherServlet源码解读
- Javascript学习笔记----String To Number
- 学习笔记:解读CppUnit源码2
- spring学习笔记之handler mapping源码解读
- jQuery源码学习笔记一(转)
- JAVA虚拟机源码学习笔记之一
- spring学习笔记之AbstractController源码解读
- Ubuntu学习笔记(1)---编译源码包