--- old/src/share/classes/java/lang/String.java 2013-02-16 22:32:08.260026292 -0800
+++ new/src/share/classes/java/lang/String.java 2013-02-16 22:32:08.016026279 -0800
@@ -25,6 +25,7 @@
package java.lang;
+import java.io.ObjectStreamException;
import java.io.ObjectStreamField;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
@@ -110,7 +111,7 @@
public final class String
implements java.io.Serializable, Comparable, CharSequence {
/** The value is used for character storage. */
- private final char value[];
+ final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
@@ -965,6 +966,7 @@
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
+ @Override
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
@@ -983,6 +985,9 @@
}
return true;
}
+ } else if (anObject instanceof SubSequence) {
+ // turn the tables to keep this method smaller.
+ return anObject.equals(this);
}
return false;
}
@@ -1159,6 +1164,18 @@
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.
@@ -1962,18 +1979,7 @@
/**
* Returns a new character sequence that is a subsequence of this sequence.
*
- * An invocation of this method of the form
- *
- *
- * str.subSequence(begin, end)
- *
- * behaves in exactly the same way as the invocation
- *
- *
- * str.substring(begin, end)
- *
- * This method is defined so that the {@code String} class can implement
- * the {@link CharSequence} interface.
+ * @implNote The character sequence refers to the original String.
*
* @param beginIndex the begin index, inclusive.
* @param endIndex the end index, exclusive.
@@ -1987,8 +1993,210 @@
* @since 1.4
* @spec JSR-51
*/
+ @Override
public CharSequence subSequence(int beginIndex, int endIndex) {
- return this.substring(beginIndex, 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 {
+
+ /**
+ * 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();
+ }
}
/**