附加: CharSequence源码:
public interface CharSequence { /** * Returns the length of this character sequence. The length is the number * of 16-bit {@code char}s in the sequence. * * @return the number of {@code char}s in this sequence */ int length(); /** * Returns the {@code char} value at the specified index. An index ranges from zero * to {@code length() - 1}. The first {@code char} value of the sequence is at * index zero, the next at index one, and so on, as for array * indexing. * * <p>If the {@code char} value specified by the index is a * <a href="{@docRoot}/java.base/java/lang/Character.html#unicode">surrogate</a>, the surrogate * value is returned. * * @param index the index of the {@code char} value to be returned * * @return the specified {@code char} value * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} */ char charAt(int index); /** * Returns a {@code CharSequence} that is a subsequence of this sequence. * The subsequence starts with the {@code char} value at the specified index and * ends with the {@code char} value at index {@code end - 1}. The length * (in {@code char}s) of the * returned sequence is {@code end - start}, so if {@code start == end} * then an empty sequence is returned. * * @param start the start index, inclusive * @param end the end index, exclusive * * @return the specified subsequence * * @throws IndexOutOfBoundsException * if {@code start} or {@code end} are negative, * if {@code end} is greater than {@code length()}, * or if {@code start} is greater than {@code end} */ CharSequence subSequence(int start, int end); /** * Returns a string containing the characters in this sequence in the same * order as this sequence. The length of the string will be the length of * this sequence. * * @return a string consisting of exactly this sequence of characters */ public String toString(); /** * Returns a stream of {@code int} zero-extending the {@code char} values * from this sequence. Any char which maps to a <a * href="{@docRoot}/java.base/java/lang/Character.html#unicode">surrogate code * point</a> is passed through uninterpreted. * * <p>The stream binds to this sequence when the terminal stream operation * commences (specifically, for mutable sequences the spliterator for the * stream is <a href="../util/Spliterator.html#binding"><em>late-binding</em></a>). * If the sequence is modified during that operation then the result is * undefined. * * @return an IntStream of char values from this sequence * @since 1.8 */ public default IntStream chars() { class CharIterator implements PrimitiveIterator.OfInt { int cur = 0; public boolean hasNext() { return cur < length(); } public int nextInt() { if (hasNext()) { return charAt(cur++); } else { throw new NoSuchElementException(); } } @Override public void forEachRemaining(IntConsumer block) { for (; cur < length(); cur++) { block.accept(charAt(cur)); } } } return StreamSupport.intStream(() -> Spliterators.spliterator( new CharIterator(), length(), Spliterator.ORDERED), Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.ORDERED, false); } /** * Returns a stream of code point values from this sequence. Any surrogate * pairs encountered in the sequence are combined as if by {@linkplain * Character#toCodePoint Character.toCodePoint} and the result is passed * to the stream. Any other code units, including ordinary BMP characters, * unpaired surrogates, and undefined code units, are zero-extended to * {@code int} values which are then passed to the stream. * * <p>The stream binds to this sequence when the terminal stream operation * commences (specifically, for mutable sequences the spliterator for the * stream is <a href="../util/Spliterator.html#binding"><em>late-binding</em></a>). * If the sequence is modified during that operation then the result is * undefined. * * @return an IntStream of Unicode code points from this sequence * @since 1.8 */ public default IntStream codePoints() { class CodePointIterator implements PrimitiveIterator.OfInt { int cur = 0; @Override public void forEachRemaining(IntConsumer block) { final int length = length(); int i = cur; try { while (i < length) { char c1 = charAt(i++); if (!Character.isHighSurrogate(c1) || i >= length) { block.accept(c1); } else { char c2 = charAt(i); if (Character.isLowSurrogate(c2)) { i++; block.accept(Character.toCodePoint(c1, c2)); } else { block.accept(c1); } } } } finally { cur = i; } } public boolean hasNext() { return cur < length(); } public int nextInt() { final int length = length(); if (cur >= length) { throw new NoSuchElementException(); } char c1 = charAt(cur++); if (Character.isHighSurrogate(c1) && cur < length) { char c2 = charAt(cur); if (Character.isLowSurrogate(c2)) { cur++; return Character.toCodePoint(c1, c2); } } return c1; } } return StreamSupport.intStream(() -> Spliterators.spliteratorUnknownSize( new CodePointIterator(), Spliterator.ORDERED), Spliterator.ORDERED, false); } /** * Compares two {@code CharSequence} instances lexicographically. Returns a * negative value, zero, or a positive value if the first sequence is lexicographically * less than, equal to, or greater than the second, respectively. * * <p> * The lexicographical ordering of {@code CharSequence} is defined as follows. * Consider a {@code CharSequence} <i>cs</i> of length <i>len</i> to be a * sequence of char values, <i>cs[0]</i> to <i>cs[len-1]</i>. Suppose <i>k</i> * is the lowest index at which the corresponding char values from each sequence * differ. The lexicographic ordering of the sequences is determined by a numeric * comparison of the char values <i>cs1[k]</i> with <i>cs2[k]</i>. If there is * no such index <i>k</i>, the shorter sequence is considered lexicographically * less than the other. If the sequences have the same length, the sequences are * considered lexicographically equal. * * * @param cs1 the first {@code CharSequence} * @param cs2 the second {@code CharSequence} * * @return the value {@code 0} if the two {@code CharSequence} are equal; * a negative integer if the first {@code CharSequence} * is lexicographically less than the second; or a * positive integer if the first {@code CharSequence} is * lexicographically greater than the second. * * @since 11 */ @SuppressWarnings("unchecked") public static int compare(CharSequence cs1, CharSequence cs2) { if (Objects.requireNonNull(cs1) == Objects.requireNonNull(cs2)) { return 0; } if (cs1.getClass() == cs2.getClass() && cs1 instanceof Comparable) { return ((Comparable<Object>) cs1).compareTo(cs2); } for (int i = 0, len = Math.min(cs1.length(), cs2.length()); i < len; i++) { char a = cs1.charAt(i); char b = cs2.charAt(i); if (a != b) { return a - b; } } return cs1.length() - cs2.length(); } }CharSequence是什么? 这是一个接口,下面String源码就实现了这个接口,还有StringBuild和StringBuffer两个类也是这个接口的实现类。 CharSequence主要就是实现了一些主要的方法。
String为什么不可变? 因为String对象内部维护了一个final的char数组,当new 一个String对象的时候,会将字符串分割维护为char数组,所以要是更改的话就需要改变char数组,但是char数组是final的,不可改变的,所以不能改变String值。
String的equals方法: equals方法源码:
private final char value[]; //value是String维护的char数组 public boolean equals(Object anObject) { //如果当前字符串和要比对的对象是同一个就直接返回true if (this == anObject) { return true; } //如果比对的对象是String字符串对象 if (anObject instanceof String) { //将对象强转为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) { //有一个不相同就直接返回false if (v1[i] != v2[i]) return false; i++; } return true; } } //不是返回false return false; }重点都在注释里面写了!
String的hashCode方法:
private int hash; // Default to 0 //下面这是hashCode方法自带注释 /** * Returns a hash code for this string. The hash code for a * {@code String} object is computed as * <blockquote><pre> * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] * </pre></blockquote> * using {@code int} arithmetic, where {@code s[i]} is the * <i>i</i>th character of the string, {@code n} is the length of * the string, and {@code ^} indicates exponentiation. * (The hash value of the empty string is zero.) * * @return a hash code value for this object. */ public int hashCode() { int h = hash; //h为0说明没有进行hash,只是初始值;value有值说明已经由String了 if (h == 0 && value.length > 0) { char val[] = value; //遍历字符串的字符 for (int i = 0; i < value.length; i++) { //val[0]*31^(n-1) + val[1]*31^(n-2) + ... + val[n-1] h = 31 * h + val[i]; } hash = h; } //进行缓存,否则说明已经进行hash了,直接返回即可 return h; }很明显,只有第一次hashCode调用会计算hash值,后面的调用只是取hash值(hash相当于一个缓存),返回即可。
String的intern方法:
/** * Returns a canonical representation for the string object. * <p> * A pool of strings, initially empty, is maintained privately by the * class {@code String}. * <p> * When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned. * <p> * It follows that for any two strings {@code s} and {@code t}, * {@code s.intern() == t.intern()} is {@code true} * if and only if {@code s.equals(t)} is {@code true}. * <p> * All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * <cite>The Java™ Language Specification</cite>. * * @return a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. */ public native String intern();这个intern方法是个本地方法,所以没有源码了,看了上面的注释发现:就是将字符串放入到字符串常量池中,如果下次在进行new字符串,就会从常量池中取出来。