< prev index next >

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

Print this page

        

@@ -73,11 +73,11 @@
  * Here are some more examples of how strings can be used:
  * <blockquote><pre>
  *     System.out.println("abc");
  *     String cde = "cde";
  *     System.out.println("abc" + cde);
- *     String c = "abc".substring(2, 3);
+ *     String c = "abc".substring(2,3);
  *     String d = cde.substring(1, 2);
  * </pre></blockquote>
  * <p>
  * The class {@code String} includes methods for examining
  * individual characters of the sequence, for comparing strings, for

@@ -162,16 +162,10 @@
     private final byte coder;
 
     /** Cache the hash code for the string */
     private int hash; // Default to 0
 
-    /**
-     * Cache if the hash has been calculated as actually being zero, enabling
-     * us to avoid recalculating this.
-     */
-    private boolean hashIsZero; // Default to false;
-
     /** use serialVersionUID from JDK 1.0.2 for interoperability */
     private static final long serialVersionUID = -6849794470754667710L;
 
     /**
      * If String compaction is disabled, the bytes in {@code value} are

@@ -1018,12 +1012,13 @@
         if (this == anObject) {
             return true;
         }
         if (anObject instanceof String) {
             String aString = (String)anObject;
-            if (!COMPACT_STRINGS || this.coder == aString.coder) {
-                return StringLatin1.equals(value, aString.value);
+            if (coder() == aString.coder()) {
+                return isLatin1() ? StringLatin1.equals(value, aString.value)
+                                  : StringUTF16.equals(value, aString.value);
             }
         }
         return false;
     }
 

@@ -1054,20 +1049,19 @@
         if (len != sb.length()) {
             return false;
         }
         byte v1[] = value;
         byte v2[] = sb.getValue();
-        byte coder = coder();
-        if (coder == sb.getCoder()) {
+        if (coder() == sb.getCoder()) {
             int n = v1.length;
             for (int i = 0; i < n; i++) {
                 if (v1[i] != v2[i]) {
                     return false;
                 }
             }
         } else {
-            if (coder != LATIN1) {  // utf16 str and latin1 abs can never be "equal"
+            if (!isLatin1()) {  // utf16 str and latin1 abs can never be "equal"
                 return false;
             }
             return StringUTF16.contentEquals(v1, v2, len);
         }
         return true;

@@ -1207,17 +1201,16 @@
      *          lexicographically greater than the string argument.
      */
     public int compareTo(String anotherString) {
         byte v1[] = value;
         byte v2[] = anotherString.value;
-        byte coder = coder();
-        if (coder == anotherString.coder()) {
-            return coder == LATIN1 ? StringLatin1.compareTo(v1, v2)
-                                   : StringUTF16.compareTo(v1, v2);
+        if (coder() == anotherString.coder()) {
+            return isLatin1() ? StringLatin1.compareTo(v1, v2)
+                              : StringUTF16.compareTo(v1, v2);
         }
-        return coder == LATIN1 ? StringLatin1.compareToUTF16(v1, v2)
-                               : StringUTF16.compareToLatin1(v1, v2);
+        return isLatin1() ? StringLatin1.compareToUTF16(v1, v2)
+                          : StringUTF16.compareToLatin1(v1, v2);
      }
 
     /**
      * A Comparator that orders {@code String} objects as by
      * {@code compareToIgnoreCase}. This comparator is serializable.

@@ -1237,17 +1230,16 @@
         private static final long serialVersionUID = 8575799808933029326L;
 
         public int compare(String s1, String s2) {
             byte v1[] = s1.value;
             byte v2[] = s2.value;
-            byte coder = s1.coder();
-            if (coder == s2.coder()) {
-                return coder == LATIN1 ? StringLatin1.compareToCI(v1, v2)
-                                       : StringUTF16.compareToCI(v1, v2);
+            if (s1.coder() == s2.coder()) {
+                return s1.isLatin1() ? StringLatin1.compareToCI(v1, v2)
+                                     : StringUTF16.compareToCI(v1, v2);
             }
-            return coder == LATIN1 ? StringLatin1.compareToCI_UTF16(v1, v2)
-                                   : StringUTF16.compareToCI_Latin1(v1, v2);
+            return s1.isLatin1() ? StringLatin1.compareToCI_UTF16(v1, v2)
+                                 : StringUTF16.compareToCI_Latin1(v1, v2);
         }
 
         /** Replaces the de-serialized object. */
         private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
     }

@@ -1317,12 +1309,11 @@
         if ((ooffset < 0) || (toffset < 0) ||
              (toffset > (long)length() - len) ||
              (ooffset > (long)other.length() - len)) {
             return false;
         }
-        byte coder = coder();
-        if (coder == other.coder()) {
+        if (coder() == other.coder()) {
             if (!isLatin1() && (len > 0)) {
                 toffset = toffset << 1;
                 ooffset = ooffset << 1;
                 len = len << 1;
             }

@@ -1330,11 +1321,11 @@
                 if (tv[toffset++] != ov[ooffset++]) {
                     return false;
                 }
             }
         } else {
-            if (coder == LATIN1) {
+            if (coder() == LATIN1) {
                 while (len-- > 0) {
                     if (StringLatin1.getChar(tv, toffset++) !=
                         StringUTF16.getChar(ov, ooffset++)) {
                         return false;
                     }

@@ -1412,17 +1403,16 @@
                 || (ooffset > (long)other.length() - len)) {
             return false;
         }
         byte tv[] = value;
         byte ov[] = other.value;
-        byte coder = coder();
-        if (coder == other.coder()) {
-            return coder == LATIN1
+        if (coder() == other.coder()) {
+            return isLatin1()
               ? StringLatin1.regionMatchesCI(tv, toffset, ov, ooffset, len)
               : StringUTF16.regionMatchesCI(tv, toffset, ov, ooffset, len);
         }
-        return coder == LATIN1
+        return isLatin1()
               ? StringLatin1.regionMatchesCI_UTF16(tv, toffset, ov, ooffset, len)
               : StringUTF16.regionMatchesCI_Latin1(tv, toffset, ov, ooffset, len);
     }
 
     /**

@@ -1449,20 +1439,19 @@
         }
         byte ta[] = value;
         byte pa[] = prefix.value;
         int po = 0;
         int pc = pa.length;
-        byte coder = coder();
-        if (coder == prefix.coder()) {
-            int to = (coder == LATIN1) ? toffset : toffset << 1;
+        if (coder() == prefix.coder()) {
+            int to = isLatin1() ? toffset : toffset << 1;
             while (po < pc) {
                 if (ta[to++] != pa[po++]) {
                     return false;
                 }
             }
         } else {
-            if (coder == LATIN1) {  // && pcoder == UTF16
+            if (isLatin1()) {  // && pcoder == UTF16
                 return false;
             }
             // coder == UTF16 && pcoder == LATIN1)
             while (po < pc) {
                 if (StringUTF16.getChar(ta, toffset++) != (pa[po++] & 0xff)) {

@@ -1517,25 +1506,18 @@
      * (The hash value of the empty string is zero.)
      *
      * @return  a hash code value for this object.
      */
     public int hashCode() {
-        // The hash or hashIsZero fields are subject to a benign data race,
-        // making it crucial to ensure that any observable result of the
-        // calculation in this method stays correct under any possible read of
-        // these fields. Necessary restrictions to allow this to be correct
-        // without explicit memory fences or similar concurrency primitives is
-        // that we can ever only write to one of these two fields for a given
-        // String instance, and that the computation is idempotent and derived
-        // from immutable state
         int h = hash;
-        if (h == 0 && !hashIsZero) {
+        if (h == 0 && value.length > 0) {
             h = isLatin1() ? StringLatin1.hashCode(value)
                            : StringUTF16.hashCode(value);
-            if (h == 0) {
-                hashIsZero = true;
-            } else {
+            // Avoid issuing a store if the calculated value is also zero:
+            // in addition to a minor performance benefit, this allows storing
+            // Strings with zero hash code in read-only memory.
+            if (h != 0) {
                 hash = h;
             }
         }
         return h;
     }

@@ -1691,16 +1673,15 @@
      * @param   str   the substring to search for.
      * @return  the index of the first occurrence of the specified substring,
      *          or {@code -1} if there is no such occurrence.
      */
     public int indexOf(String str) {
-        byte coder = coder();
-        if (coder == str.coder()) {
+        if (coder() == str.coder()) {
             return isLatin1() ? StringLatin1.indexOf(value, str.value)
                               : StringUTF16.indexOf(value, str.value);
         }
-        if (coder == LATIN1) {  // str.coder == UTF16
+        if (coder() == LATIN1) {  // str.coder == UTF16
             return -1;
         }
         return StringUTF16.indexOfLatin1(value, str.value);
     }
 

@@ -1969,11 +1950,24 @@
      */
     public String concat(String str) {
         if (str.isEmpty()) {
             return this;
         }
-        return StringConcatHelper.simpleConcat(this, str);
+        if (coder() == str.coder()) {
+            byte[] val = this.value;
+            byte[] oval = str.value;
+            int len = val.length + oval.length;
+            byte[] buf = Arrays.copyOf(val, len);
+            System.arraycopy(oval, 0, buf, val.length, oval.length);
+            return new String(buf, coder);
+        }
+        int len = length();
+        int olen = str.length();
+        byte[] buf = StringUTF16.newBytesFor(len + olen);
+        getBytes(buf, 0, UTF16);
+        str.getBytes(buf, len, UTF16);
+        return new String(buf, UTF16);
     }
 
     /**
      * Returns a string resulting from replacing all occurrences of
      * {@code oldChar} in this string with {@code newChar}.

@@ -2158,52 +2152,31 @@
      * @param  replacement The replacement sequence of char values
      * @return  The resulting string
      * @since 1.5
      */
     public String replace(CharSequence target, CharSequence replacement) {
-        String trgtStr = target.toString();
+        String tgtStr = target.toString();
         String replStr = replacement.toString();
-        int thisLen = length();
-        int trgtLen = trgtStr.length();
-        int replLen = replStr.length();
-
-        if (trgtLen > 0) {
-            if (trgtLen == 1 && replLen == 1) {
-                return replace(trgtStr.charAt(0), replStr.charAt(0));
-            }
-
-            boolean thisIsLatin1 = this.isLatin1();
-            boolean trgtIsLatin1 = trgtStr.isLatin1();
-            boolean replIsLatin1 = replStr.isLatin1();
-            String ret = (thisIsLatin1 && trgtIsLatin1 && replIsLatin1)
-                    ? StringLatin1.replace(value, thisLen,
-                                           trgtStr.value, trgtLen,
-                                           replStr.value, replLen)
-                    : StringUTF16.replace(value, thisLen, thisIsLatin1,
-                                          trgtStr.value, trgtLen, trgtIsLatin1,
-                                          replStr.value, replLen, replIsLatin1);
-            if (ret != null) {
-                return ret;
-            }
+        int j = indexOf(tgtStr);
+        if (j < 0) {
             return this;
-
-        } else { // trgtLen == 0
-            int resultLen;
-            try {
-                resultLen = Math.addExact(thisLen, Math.multiplyExact(
-                        Math.addExact(thisLen, 1), replLen));
-            } catch (ArithmeticException ignored) {
-                throw new OutOfMemoryError();
-            }
-
-            StringBuilder sb = new StringBuilder(resultLen);
-            sb.append(replStr);
-            for (int i = 0; i < thisLen; ++i) {
-                sb.append(charAt(i)).append(replStr);
-            }
-            return sb.toString();
         }
+        int tgtLen = tgtStr.length();
+        int tgtLen1 = Math.max(tgtLen, 1);
+        int thisLen = length();
+
+        int newLenHint = thisLen - tgtLen + replStr.length();
+        if (newLenHint < 0) {
+            throw new OutOfMemoryError();
+        }
+        StringBuilder sb = new StringBuilder(newLenHint);
+        int i = 0;
+        do {
+            sb.append(this, i, j).append(replStr);
+            i = j + tgtLen;
+        } while (j < thisLen && (j = indexOf(tgtStr, j + tgtLen1)) > 0);
+        return sb.append(this, i, thisLen).toString();
     }
 
     /**
      * Splits this string around matches of the given
      * <a href="../util/regex/Pattern.html#sum">regular expression</a>.
< prev index next >