src/share/classes/java/lang/String.java

Print this page
rev 6546 : 7197183: Alternate implementation of String.subSequence which uses shared backing array.
Reviewed-by: duke

*** 23,32 **** --- 23,33 ---- * questions. */ package java.lang; + import java.io.ObjectStreamException; import java.io.ObjectStreamField; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays;
*** 108,118 **** */ public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ ! private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ --- 109,119 ---- */ public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ ! final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */
*** 963,972 **** --- 964,974 ---- * equivalent to this string, {@code false} otherwise * * @see #compareTo(String) * @see #equalsIgnoreCase(String) */ + @Override public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) {
*** 981,990 **** --- 983,995 ---- return false; i++; } return true; } + } else if (anObject instanceof SubSequence) { + // turn the tables to keep this method smaller. + return anObject.equals(this); } return false; } /**
*** 1157,1166 **** --- 1162,1183 ---- k++; } return len1 - len2; } + // This is the method we want instead of the default bridge. + // public int compareTo(Object other) { + // if(other instanceof String) { + // return compareTo((String) other); + // } else if (other instanceof SubSequence) { + // // delegate to keep this method small. + // return - ((SubSequence) other).compareTo(this); + // } else { + // throw new ClassCastException(); + // } + // } + // /** * A Comparator that orders {@code String} objects as by * {@code compareToIgnoreCase}. This comparator is serializable. * <p> * Note that this Comparator does <em>not</em> take locale into account,
*** 1960,1981 **** } /** * Returns a new character sequence that is a subsequence of this sequence. * ! * <p> An invocation of this method of the form ! * ! * <blockquote><pre> ! * str.subSequence(begin,&nbsp;end)</pre></blockquote> ! * ! * behaves in exactly the same way as the invocation ! * ! * <blockquote><pre> ! * str.substring(begin,&nbsp;end)</pre></blockquote> ! * ! * This method is defined so that the {@code String} class can implement ! * the {@link CharSequence} interface. </p> * * @param beginIndex the begin index, inclusive. * @param endIndex the end index, exclusive. * @return the specified subsequence. * --- 1977,1987 ---- } /** * Returns a new character sequence that is a subsequence of this sequence. * ! * @implNote The character sequence refers to the original String. * * @param beginIndex the begin index, inclusive. * @param endIndex the end index, exclusive. * @return the specified subsequence. *
*** 1985,1996 **** * or if {@code beginIndex} is greater than {@code endIndex} * * @since 1.4 * @spec JSR-51 */ public CharSequence subSequence(int beginIndex, int endIndex) { ! return this.substring(beginIndex, endIndex); } /** * Concatenates the specified string to the end of this string. * <p> --- 1991,2204 ---- * or if {@code beginIndex} is greater than {@code endIndex} * * @since 1.4 * @spec JSR-51 */ + @Override public CharSequence subSequence(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 (subLen == value.length) ! ? this ! : new SubSequence(this, beginIndex, subLen); ! } ! ! /** ! * A CharSequence implemented as a sub-sequence of a String. ! */ ! private final static class SubSequence implements ! java.io.Serializable, CharSequence, Comparable<CharSequence> { ! ! /** ! * The String of which we are a sub-sequence. ! */ ! private final String source; ! ! /** ! * The offset within the String of our first character. ! */ ! private final int offset; ! ! /** ! * The number of characters in this sub-sequence. ! */ ! private final int count; ! ! /** ! * Cached hash code value. ! */ ! private int hashCache = 0; ! ! /** ! * Construct a new sub-sequence. ! * ! * @implNote Input values are not validated. ! * ! * @param source The String of which we are a sub-sequence. ! * @param offset The offset within the String of our first character. ! * @param count The number of characters in this sub-sequence. ! */ ! SubSequence(String source, int offset, int count) { ! this.source = source; ! this.offset = offset; ! this.count = count; ! } ! ! @Override ! public boolean equals(Object other) { ! if (other == this) { ! // it's me! ! return true; ! } ! ! final char[] val1 = source.value; ! int offset1 = offset; ! final char[] val2; ! int offset2; ! int each; ! if (other instanceof SubSequence) { ! SubSequence likeMe = (SubSequence)other; ! val2 = likeMe.source.value; ! offset2 = likeMe.offset; ! each = likeMe.count; ! } else if (other instanceof String) { ! String similar = (String)other; ! val2 = similar.value; ! offset2 = 0; ! each = similar.value.length; ! } else { ! // not of recognized type. ! return false; ! } ! ! if (each != count) { ! // not the same length ! return false; ! } ! ! offset1 += each; ! offset2 += each; ! while (--each >= 0) { ! if (val1[--offset1] != val2[--offset2]) { ! // unequal char ! return false; ! } ! } ! ! // chars were all equal. ! return true; ! } ! ! /** ! * Return the hash code value for this object. ! * ! * @implSpec The hash code of a SubSequence is the same as that of a ! * String containing the same characters. ! * ! * @return a hash code value for this object. ! */ ! @Override ! public int hashCode() { ! int h = hashCache; ! if (h == 0 && count > 0) { ! char val[] = source.value; // avoid getfield opcode ! for (int i = 0; i < count; i++) { ! h = 31 * h + val[offset + i]; ! } ! ! // harmless data race updating hashCache. ! hashCache = h; ! } ! ! return h; ! } ! ! @Override ! public String toString() { ! return new String(source.value, offset, count); ! } ! ! public boolean isEmpty() { ! return count == 0; ! } ! ! ! @Override ! public int compareTo(CharSequence other) { ! int otherLen = other.length(); ! for(int each=0; each < count; each++) { ! if(each >= otherLen) { ! return 1; ! } ! ! int diff = other.charAt(each) - source.value[offset+each]; ! ! if(0 == diff) { ! continue; ! } ! ! return diff; ! } ! ! return (otherLen > count) ? -1 : 0; ! } ! ! @Override ! public int length() { ! return count; ! } ! ! @Override ! public char charAt(int index) { ! if(index < 0 || index >= count) { ! throw new IndexOutOfBoundsException(); ! } ! return source.value[offset+index]; ! } ! ! @Override ! public CharSequence subSequence(int start, int end) { ! int len = end - start; ! if (start < 0 || ! end < start || ! len > count) { ! throw new IndexOutOfBoundsException(); ! } ! ! if (0 == len) { ! // it's empty. ! return new String(); ! } ! ! if(start == 0 && len == count) { ! // exactly the same sequence. ! return this; ! } ! ! // create an even smaller sub-sequence ! return new SubSequence(source, offset+start, len); ! } ! ! /** ! * {@inheritDoc} ! * ! * @implNote We replace this sub-sequence with a String containing the ! * same sequence of characters. ! */ ! public Object writeReplace() throws ObjectStreamException { ! // It's better to just replace with string. ! return toString(); ! } } /** * Concatenates the specified string to the end of this string. * <p>