Java source code to read notes (a) String

The underlying source code to read, to improve their ability to Java foundation.

Note a:

public final class String

String class is defined by the final modification. If the class with final modifications, will indicate that this class can not be inherited.

Note II: Global Variables

/** The value is used for character storage. */
private final char value[];

Here the character string memory array definition used, the bottom can be found String operation is carried out by the array of characters. Note here that the array defined in two ways.

  1. int[] a1
  2. A1 int []
    the same manner as the above two effects a defined array of type int a1.
/** Cache the hash code for the string */
    private int hash; // Default to 0

Hash value, default 0, is a cache of hashcode of the String instance. String comparison is often used because, as the hashcode, if required each time for comparing calculated hashcode value, the more trouble.

public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();

In fact, this static constant is used to compare two strings ignoring the case.

Note III: constructor

public String() {
        this.value = "".value;
    }

Create an empty character sequence, so little meaning, because String is immutable.

public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

A String as a parameter, create a string object.

 public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

An array of characters to create a string object as a parameter, modify the character array does not affect the string object is created.

public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= value.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

With a given character array, select part of creating a String object
There are too many parameters String constructor may receive String, char [], byte [], StringBuffer other parameters. Not list them. However, the essence is to pass the received parameters to the global variable value []. You can also pass a byte array in the constructor. But an array of bytes needed to specify character encoding.
Java differences in character (char) and byte (byte) of

  • byte occupies one byte, char occupies two bytes
  • byte as a signed type, may represent a negative number, char is unsigned, negative numbers can not
  • For English, the two can be interchangeable

Note Four: internal class

String class is only one class interior

private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;

        public int compare(String s1, String s2) {
            int n1 = s1.length();
            int n2 = s2.length();
            int min = Math.min(n1, n2);
            for (int i = 0; i < min; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    if (c1 != c2) {
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        if (c1 != c2) {
                            // No overflow because of numeric promotion
                            return c1 - c2;
                        }
                    }
                }
            }
            return n1 - n2;
        }

There is already a compareTo () method, and why do you need this class. In fact, in order to code reuse, the difference between this class and compareTo () is that this method can ignore the case when comparing to compare. Secondly, compareToIgnoreCase methods of the String class method is provided to call the internal class implementation.

Note Five: common method

// 返回字符串对象的字符数
 public int length() {
        return value.length;
    }

--------------------------------------
// 判断字符串对象是否为空
public boolean isEmpty() {
        return value.length == 0;
    }

--------------------------------------
// 返回字符数组中指定索引的值
public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }
--------------------------------------
// 比较字符对象,忽略大小写
public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true
                : (anotherString != null)
                && (anotherString.value.length == value.length)
                && regionMatches(true, 0, anotherString, 0, value.length);
    }
--------------------------------------
// 检测字符串对象在tooffset位置是否由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;
    }

--------------------------------------
// 检测字符串是否以suffix字符串结尾
 public boolean endsWith(String suffix) {
        return startsWith(suffix, value.length - suffix.value.length);
    }

Know the underlying String class after the array of characters, will understand the method described above it is in fact operating an array of characters.
Can be seen in the following two overloaded methods are essentially calling System.arraycopy () function, in the jdk source are so many, it seems there are a number of heavy-duty, in fact, is essentially a call to the same function, but It will give you a different default initial value.

// 将字符串复制到字符数组dst中
 void getChars(char dst[], int dstBegin) {
        System.arraycopy(value, 0, dst, dstBegin, value.length);
    }

public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }

In addition to the above said equals () method, there are only relatively content contentEquals () method, which is mainly used to compare whether String, StringBuffer, StringBuild of the same content. Method for parameter CharSequence, may be known to StringBuffer, StringBuild also achieved CharSequence. Source parameters to determine which one instance, and then adopt a different strategy. But the essence is to determine whether or not the same for the same through the loop.

 public boolean contentEquals(CharSequence cs) {
        // Argument is a StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {
            if (cs instanceof StringBuffer) {
                synchronized(cs) {
                   return nonSyncContentEquals((AbstractStringBuilder)cs);
                }
            } else {
                return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        }
        // Argument is a String
        if (cs instanceof String) {
            return equals(cs);
        }
        // Argument is a generic CharSequence
        char v1[] = value;
        int n = v1.length;
        if (n != cs.length()) {
            return false;
        }
        for (int i = 0; i < n; i++) {
            if (v1[i] != cs.charAt(i)) {
                return false;
            }
        }
        return true;
    }

The following method returns the index of the specified character, Character.MIN_SUPPLEMENTARY_CODE_POINT show usually in the java char value is smaller than the storage of 0x010000. When larger than this value, it is the supplementary characters.

public int indexOf(int ch, int fromIndex) {
        final int max = value.length;
        if (fromIndex < 0) {
            fromIndex = 0;
        } else if (fromIndex >= max) {
            // Note: fromIndex might be near -1>>>1.
            return -1;
        }

        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[] value = this.value;
            for (int i = fromIndex; i < max; i++) {
                if (value[i] == ch) {
                    return i;
                }
            }
            return -1;
        } else {
            return indexOfSupplementary(ch, fromIndex);
        }
    }
    
// 和上面的相反
public int lastIndexOf(int ch, int fromIndex) {
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[] value = this.value;
            int i = Math.min(fromIndex, value.length - 1);
            for (; i >= 0; i--) {
                if (value[i] == ch) {
                    return i;
                }
            }
            return -1;
        } else {
            return lastIndexOfSupplementary(ch, fromIndex);
        }
    }

Connecting the specified string to the end of the 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);
    }

Note six: an important method

A, equals method

Before discussing euquls method, we need to look at the "==" usage, when compared to the basic types, "==" comparison of their value at the time of reference types are compared, the comparison == objects stored in memory address. equals method compares the contents of the two strings are the same. The reason why the string as Map [key, value] of the key, the key is equals () method.

 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;
    }
Two, compareTo method

First, traversing two character array, compare, and so if we are not to return the difference of characters. If the smallest been traversed character array are found in front of the characters are equal, the difference between two strings.

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;
    }
Three, hashCode method

Here it is not clear why the election 31

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;
    }
Four, startsWith () method

Determine whether a string begins with prefix at a certain position.

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

// 利用重载,判断字符串是否以prefix开头 
public boolean startsWith(String prefix) {
        return startsWith(prefix, 0);
    }

// 换个顺序而已
public boolean endsWith(String suffix) {
        return startsWith(suffix, value.length - suffix.value.length);
    }
Five, substring () method

Cutting the string specified location, where the use of a String class constructor.

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

Six, replace () method

Nice write the code, the replacement string of a single character.

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;
    }
Seven, trim () method

Delete the string end to end of the space, by comparison, to find the beginning and end of the index is not a space, and then the original string to be cut.

public String trim() {
        int len = value.length;
        int st = 0;
        char[] val = value;    /* avoid getfield opcode */

        while ((st < len) && (val[st] <= ' ')) {
            st++;
        }
        while ((st < len) && (val[len - 1] <= ' ')) {
            len--;
        }
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    }

Summary: Here, most of the source string to the end of the reading, which some method is not used, there is no Tieshanglai.

  • It has not created a string variable
  • Character string array to achieve the underlying dependence, String class are many ways in the operation of the character array
  • Operation of the character string, such as subString (), concat () method, etc., returns a new string.
  • Some source code written in nice and need a good understanding, strive for integration into their own programming style
Published 66 original articles · won praise 26 · views 10000 +

Guess you like

Origin blog.csdn.net/Time__Lc/article/details/100864507