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

学习笔记之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);

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;
}

大致就讲解以上几个方法,只是简单的从逻辑角度去分析了一些方法的实现方式和特性,因为是初学,只能先看其形,观其貌。。对其中的设计思路以及思想,和深入的特性理解并没有做过多的解析,因为这可能需要一定的积累,如果有什么建议可以在下面留言~。

欢迎大家发表自己的想法,或者有更深入的见解也可以教教我~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jdk 源码 string