Source for java.lang.String

   1: /* String.java -- immutable character sequences; the object of string literals
   2:    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
   3:    Free Software Foundation, Inc.
   4: 
   5: This file is part of GNU Classpath.
   6: 
   7: GNU Classpath is free software; you can redistribute it and/or modify
   8: it under the terms of the GNU General Public License as published by
   9: the Free Software Foundation; either version 2, or (at your option)
  10: any later version.
  11: 
  12: GNU Classpath is distributed in the hope that it will be useful, but
  13: WITHOUT ANY WARRANTY; without even the implied warranty of
  14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15: General Public License for more details.
  16: 
  17: You should have received a copy of the GNU General Public License
  18: along with GNU Classpath; see the file COPYING.  If not, write to the
  19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20: 02110-1301 USA.
  21: 
  22: Linking this library statically or dynamically with other modules is
  23: making a combined work based on this library.  Thus, the terms and
  24: conditions of the GNU General Public License cover the whole
  25: combination.
  26: 
  27: As a special exception, the copyright holders of this library give you
  28: permission to link this library with independent modules to produce an
  29: executable, regardless of the license terms of these independent
  30: modules, and to copy and distribute the resulting executable under
  31: terms of your choice, provided that you also meet, for each linked
  32: independent module, the terms and conditions of the license of that
  33: module.  An independent module is a module which is not derived from
  34: or based on this library.  If you modify this library, you may extend
  35: this exception to your version of the library, but you are not
  36: obligated to do so.  If you do not wish to do so, delete this
  37: exception statement from your version. */
  38: 
  39: 
  40: package java.lang;
  41: 
  42: import gnu.java.lang.CharData;
  43: 
  44: import java.io.Serializable;
  45: import java.io.UnsupportedEncodingException;
  46: import java.nio.ByteBuffer;
  47: import java.nio.CharBuffer;
  48: import java.nio.charset.CharacterCodingException;
  49: import java.nio.charset.Charset;
  50: import java.nio.charset.CharsetDecoder;
  51: import java.nio.charset.CharsetEncoder;
  52: import java.nio.charset.CodingErrorAction;
  53: import java.nio.charset.IllegalCharsetNameException;
  54: import java.nio.charset.UnsupportedCharsetException;
  55: import java.text.Collator;
  56: import java.util.Comparator;
  57: import java.util.Formatter;
  58: import java.util.Locale;
  59: import java.util.regex.Matcher;
  60: import java.util.regex.Pattern;
  61: import java.util.regex.PatternSyntaxException;
  62: 
  63: /**
  64:  * Strings represent an immutable set of characters.  All String literals
  65:  * are instances of this class, and two string literals with the same contents
  66:  * refer to the same String object.
  67:  *
  68:  * <p>This class also includes a number of methods for manipulating the
  69:  * contents of strings (of course, creating a new object if there are any
  70:  * changes, as String is immutable). Case mapping relies on Unicode 3.0.0
  71:  * standards, where some character sequences have a different number of
  72:  * characters in the uppercase version than the lower case.
  73:  *
  74:  * <p>Strings are special, in that they are the only object with an overloaded
  75:  * operator. When you use '+' with at least one String argument, both
  76:  * arguments have String conversion performed on them, and another String (not
  77:  * guaranteed to be unique) results.
  78:  *
  79:  * <p>String is special-cased when doing data serialization - rather than
  80:  * listing the fields of this class, a String object is converted to a string
  81:  * literal in the object stream.
  82:  *
  83:  * @author Paul N. Fisher
  84:  * @author Eric Blake (ebb9@email.byu.edu)
  85:  * @author Per Bothner (bothner@cygnus.com)
  86:  * @author Tom Tromey (tromey@redhat.com)
  87:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  88:  * @since 1.0
  89:  * @status updated to 1.4; but could use better data sharing via offset field
  90:  */
  91: public final class String
  92:   implements Serializable, Comparable<String>, CharSequence
  93: {
  94:   // WARNING: String is a CORE class in the bootstrap cycle. See the comments
  95:   // in vm/reference/java/lang/Runtime for implications of this fact.
  96: 
  97:   /**
  98:    * This is probably not necessary because this class is special cased already
  99:    * but it will avoid showing up as a discrepancy when comparing SUIDs.
 100:    */
 101:   private static final long serialVersionUID = -6849794470754667710L;
 102: 
 103:   /**
 104:    * Stores unicode multi-character uppercase expansion table.
 105:    * @see #toUpperCase(Locale)
 106:    * @see CharData#UPPER_EXPAND
 107:    */
 108:   private static final char[] upperExpand
 109:     = zeroBasedStringValue(CharData.UPPER_EXPAND);
 110: 
 111:   /**
 112:    * Stores unicode multi-character uppercase special casing table.
 113:    * @see #upperCaseExpansion(char)
 114:    * @see CharData#UPPER_SPECIAL
 115:    */
 116:   private static final char[] upperSpecial
 117:       = zeroBasedStringValue(CharData.UPPER_SPECIAL);
 118:   
 119:   /**
 120:    * Characters which make up the String.
 121:    * Package access is granted for use by StringBuffer.
 122:    */
 123:   final char[] value;
 124: 
 125:   /**
 126:    * Holds the number of characters in value.  This number is generally
 127:    * the same as value.length, but can be smaller because substrings and
 128:    * StringBuffers can share arrays. Package visible for use by trusted code.
 129:    */
 130:   final int count;
 131: 
 132:   /**
 133:    * Caches the result of hashCode().  If this value is zero, the hashcode
 134:    * is considered uncached (even if 0 is the correct hash value).
 135:    */
 136:   private int cachedHashCode;
 137: 
 138:   /**
 139:    * Holds the starting position for characters in value[].  Since
 140:    * substring()'s are common, the use of offset allows the operation
 141:    * to perform in O(1). Package access is granted for use by StringBuffer.
 142:    */
 143:   final int offset;
 144: 
 145:   /**
 146:    * An implementation for {@link #CASE_INSENSITIVE_ORDER}.
 147:    * This must be {@link Serializable}. The class name is dictated by
 148:    * compatibility with Sun's JDK.
 149:    */
 150:   private static final class CaseInsensitiveComparator
 151:     implements Comparator<String>, Serializable
 152:   {
 153:     /**
 154:      * Compatible with JDK 1.2.
 155:      */
 156:     private static final long serialVersionUID = 8575799808933029326L;
 157: 
 158:     /**
 159:      * The default private constructor generates unnecessary overhead.
 160:      */
 161:     CaseInsensitiveComparator() {}
 162: 
 163:     /**
 164:      * Compares to Strings, using
 165:      * <code>String.compareToIgnoreCase(String)</code>.
 166:      *
 167:      * @param o1 the first string
 168:      * @param o2 the second string
 169:      * @return &lt; 0, 0, or &gt; 0 depending on the case-insensitive
 170:      *         comparison of the two strings.
 171:      * @throws NullPointerException if either argument is null
 172:      * @throws ClassCastException if either argument is not a String
 173:      * @see #compareToIgnoreCase(String)
 174:      */
 175:     public int compare(String o1, String o2)
 176:     {
 177:       return o1.compareToIgnoreCase(o2);
 178:     }
 179:   } // class CaseInsensitiveComparator
 180: 
 181:   /**
 182:    * A Comparator that uses <code>String.compareToIgnoreCase(String)</code>.
 183:    * This comparator is {@link Serializable}. Note that it ignores Locale,
 184:    * for that, you want a Collator.
 185:    *
 186:    * @see Collator#compare(String, String)
 187:    * @since 1.2
 188:    */
 189:   public static final Comparator<String> CASE_INSENSITIVE_ORDER
 190:     = new CaseInsensitiveComparator();
 191: 
 192:   /**
 193:    * Creates an empty String (length 0). Unless you really need a new object,
 194:    * consider using <code>""</code> instead.
 195:    */
 196:   public String()
 197:   {
 198:     value = "".value;
 199:     offset = 0;
 200:     count = 0;
 201:   }
 202: 
 203:   /**
 204:    * Copies the contents of a String to a new String. Since Strings are
 205:    * immutable, only a shallow copy is performed.
 206:    *
 207:    * @param str String to copy
 208:    * @throws NullPointerException if value is null
 209:    */
 210:   public String(String str)
 211:   {
 212:     value = str.value;
 213:     offset = str.offset;
 214:     count = str.count;
 215:     cachedHashCode = str.cachedHashCode;
 216:   }
 217: 
 218:   /**
 219:    * Creates a new String using the character sequence of the char array.
 220:    * Subsequent changes to data do not affect the String.
 221:    *
 222:    * @param data char array to copy
 223:    * @throws NullPointerException if data is null
 224:    */
 225:   public String(char[] data)
 226:   {
 227:     this(data, 0, data.length, false);
 228:   }
 229: 
 230:   /**
 231:    * Creates a new String using the character sequence of a subarray of
 232:    * characters. The string starts at offset, and copies count chars.
 233:    * Subsequent changes to data do not affect the String.
 234:    *
 235:    * @param data char array to copy
 236:    * @param offset position (base 0) to start copying out of data
 237:    * @param count the number of characters from data to copy
 238:    * @throws NullPointerException if data is null
 239:    * @throws IndexOutOfBoundsException if (offset &lt; 0 || count &lt; 0
 240:    *         || offset + count &lt; 0 (overflow)
 241:    *         || offset + count &gt; data.length)
 242:    *         (while unspecified, this is a StringIndexOutOfBoundsException)
 243:    */
 244:   public String(char[] data, int offset, int count)
 245:   {
 246:     this(data, offset, count, false);
 247:   }
 248: 
 249:   /**
 250:    * Creates a new String using an 8-bit array of integer values, starting at
 251:    * an offset, and copying up to the count. Each character c, using
 252:    * corresponding byte b, is created in the new String as if by performing:
 253:    *
 254:    * <pre>
 255:    * c = (char) (((hibyte &amp; 0xff) &lt;&lt; 8) | (b &amp; 0xff))
 256:    * </pre>
 257:    *
 258:    * @param ascii array of integer values
 259:    * @param hibyte top byte of each Unicode character
 260:    * @param offset position (base 0) to start copying out of ascii
 261:    * @param count the number of characters from ascii to copy
 262:    * @throws NullPointerException if ascii is null
 263:    * @throws IndexOutOfBoundsException if (offset &lt; 0 || count &lt; 0
 264:    *         || offset + count &lt; 0 (overflow)
 265:    *         || offset + count &gt; ascii.length)
 266:    *         (while unspecified, this is a StringIndexOutOfBoundsException)
 267:    * @see #String(byte[])
 268:    * @see #String(byte[], String)
 269:    * @see #String(byte[], int, int)
 270:    * @see #String(byte[], int, int, String)
 271:    * @deprecated use {@link #String(byte[], int, int, String)} to perform
 272:    *             correct encoding
 273:    */
 274:   public String(byte[] ascii, int hibyte, int offset, int count)
 275:   {
 276:     if (offset < 0)
 277:       throw new StringIndexOutOfBoundsException("offset: " + offset);
 278:     if (count < 0)
 279:       throw new StringIndexOutOfBoundsException("count: " + count);
 280:     // equivalent to: offset + count < 0 || offset + count > ascii.length
 281:     if (ascii.length - offset < count)
 282:       throw new StringIndexOutOfBoundsException("offset + count: "
 283:                         + (offset + count));
 284:     value = new char[count];
 285:     this.offset = 0;
 286:     this.count = count;
 287:     hibyte <<= 8;
 288:     offset += count;
 289:     while (--count >= 0)
 290:       value[count] = (char) (hibyte | (ascii[--offset] & 0xff));
 291:   }
 292: 
 293:   /**
 294:    * Creates a new String using an 8-bit array of integer values. Each
 295:    * character c, using corresponding byte b, is created in the new String
 296:    * as if by performing:
 297:    *
 298:    * <pre>
 299:    * c = (char) (((hibyte &amp; 0xff) &lt;&lt; 8) | (b &amp; 0xff))
 300:    * </pre>
 301:    *
 302:    * @param ascii array of integer values
 303:    * @param hibyte top byte of each Unicode character
 304:    * @throws NullPointerException if ascii is null
 305:    * @see #String(byte[])
 306:    * @see #String(byte[], String)
 307:    * @see #String(byte[], int, int)
 308:    * @see #String(byte[], int, int, String)
 309:    * @see #String(byte[], int, int, int)
 310:    * @deprecated use {@link #String(byte[], String)} to perform
 311:    *             correct encoding
 312:    */
 313:   public String(byte[] ascii, int hibyte)
 314:   {
 315:     this(ascii, hibyte, 0, ascii.length);
 316:   }
 317: 
 318:   /**
 319:    * Creates a new String using the portion of the byte array starting at the
 320:    * offset and ending at offset + count. Uses the specified encoding type
 321:    * to decode the byte array, so the resulting string may be longer or
 322:    * shorter than the byte array. For more decoding control, use
 323:    * {@link java.nio.charset.CharsetDecoder}, and for valid character sets,
 324:    * see {@link java.nio.charset.Charset}. The behavior is not specified if
 325:    * the decoder encounters invalid characters; this implementation throws
 326:    * an Error.
 327:    *
 328:    * @param data byte array to copy
 329:    * @param offset the offset to start at
 330:    * @param count the number of bytes in the array to use
 331:    * @param encoding the name of the encoding to use
 332:    * @throws NullPointerException if data or encoding is null
 333:    * @throws IndexOutOfBoundsException if offset or count is incorrect
 334:    *         (while unspecified, this is a StringIndexOutOfBoundsException)
 335:    * @throws UnsupportedEncodingException if encoding is not found
 336:    * @throws Error if the decoding fails
 337:    * @since 1.1
 338:    */
 339:   public String(byte[] data, int offset, int count, String encoding)
 340:     throws UnsupportedEncodingException
 341:   {
 342:     if (offset < 0)
 343:       throw new StringIndexOutOfBoundsException("offset: " + offset);
 344:     if (count < 0)
 345:       throw new StringIndexOutOfBoundsException("count: " + count);
 346:     // equivalent to: offset + count < 0 || offset + count > data.length
 347:     if (data.length - offset < count)
 348:       throw new StringIndexOutOfBoundsException("offset + count: "
 349:                         + (offset + count));
 350:     try 
 351:       {
 352:         CharsetDecoder csd = Charset.forName(encoding).newDecoder();
 353:     csd.onMalformedInput(CodingErrorAction.REPLACE);
 354:     csd.onUnmappableCharacter(CodingErrorAction.REPLACE);
 355:     CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count));
 356:      if(cbuf.hasArray())
 357:        {
 358:          value = cbuf.array();
 359:         this.offset = cbuf.position();
 360:         this.count = cbuf.remaining();
 361:        } else {
 362:         // Doubt this will happen. But just in case.
 363:         value = new char[cbuf.remaining()];
 364:         cbuf.get(value);
 365:         this.offset = 0;
 366:         this.count = value.length;
 367:       }
 368:       } catch(CharacterCodingException e){
 369:       throw new UnsupportedEncodingException("Encoding: "+encoding+
 370:                          " not found.");      
 371:       } catch(IllegalCharsetNameException e){
 372:       throw new UnsupportedEncodingException("Encoding: "+encoding+
 373:                          " not found.");
 374:       } catch(UnsupportedCharsetException e){
 375:       throw new UnsupportedEncodingException("Encoding: "+encoding+
 376:                          " not found.");
 377:       }    
 378:   }
 379: 
 380:   /**
 381:    * Creates a new String using the byte array. Uses the specified encoding
 382:    * type to decode the byte array, so the resulting string may be longer or
 383:    * shorter than the byte array. For more decoding control, use
 384:    * {@link java.nio.charset.CharsetDecoder}, and for valid character sets,
 385:    * see {@link java.nio.charset.Charset}. The behavior is not specified if
 386:    * the decoder encounters invalid characters; this implementation throws
 387:    * an Error.
 388:    *
 389:    * @param data byte array to copy
 390:    * @param encoding the name of the encoding to use
 391:    * @throws NullPointerException if data or encoding is null
 392:    * @throws UnsupportedEncodingException if encoding is not found
 393:    * @throws Error if the decoding fails
 394:    * @see #String(byte[], int, int, String)
 395:    * @since 1.1
 396:    */
 397:   public String(byte[] data, String encoding)
 398:     throws UnsupportedEncodingException
 399:   {
 400:     this(data, 0, data.length, encoding);
 401:   }
 402: 
 403:   /**
 404:    * Creates a new String using the portion of the byte array starting at the
 405:    * offset and ending at offset + count. Uses the encoding of the platform's
 406:    * default charset, so the resulting string may be longer or shorter than
 407:    * the byte array. For more decoding control, use
 408:    * {@link java.nio.charset.CharsetDecoder}.  The behavior is not specified
 409:    * if the decoder encounters invalid characters; this implementation throws
 410:    * an Error.
 411:    *
 412:    * @param data byte array to copy
 413:    * @param offset the offset to start at
 414:    * @param count the number of bytes in the array to use
 415:    * @throws NullPointerException if data is null
 416:    * @throws IndexOutOfBoundsException if offset or count is incorrect
 417:    * @throws Error if the decoding fails
 418:    * @see #String(byte[], int, int, String)
 419:    * @since 1.1
 420:    */
 421:   public String(byte[] data, int offset, int count)
 422:   {
 423:     if (offset < 0)
 424:       throw new StringIndexOutOfBoundsException("offset: " + offset);
 425:     if (count < 0)
 426:       throw new StringIndexOutOfBoundsException("count: " + count);
 427:     // equivalent to: offset + count < 0 || offset + count > data.length
 428:     if (data.length - offset < count)
 429:       throw new StringIndexOutOfBoundsException("offset + count: "
 430:                         + (offset + count));
 431:     int o, c;
 432:     char[] v;
 433:     String encoding;
 434:     try 
 435:     {
 436:       encoding = System.getProperty("file.encoding");
 437:       CharsetDecoder csd = Charset.forName(encoding).newDecoder();
 438:       csd.onMalformedInput(CodingErrorAction.REPLACE);
 439:       csd.onUnmappableCharacter(CodingErrorAction.REPLACE);
 440:       CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count));
 441:       if(cbuf.hasArray())
 442:         {
 443:               v = cbuf.array();
 444:           o = cbuf.position();
 445:           c = cbuf.remaining();
 446:         } else {
 447:           // Doubt this will happen. But just in case.
 448:           v = new char[cbuf.remaining()];
 449:           cbuf.get(v);
 450:           o = 0;
 451:           c = v.length;
 452:         }
 453:     } catch(Exception ex){
 454:         // If anything goes wrong (System property not set,
 455:         // NIO provider not available, etc)
 456:         // Default to the 'safe' encoding ISO8859_1
 457:         v = new char[count];
 458:         o = 0;
 459:         c = count;
 460:         for (int i=0;i<count;i++)
 461:           v[i] = (char)data[offset+i];
 462:     }
 463:     this.value = v;
 464:     this.offset = o;
 465:     this.count = c;
 466:   }
 467: 
 468:   /**
 469:    * Creates a new String using the byte array. Uses the encoding of the
 470:    * platform's default charset, so the resulting string may be longer or
 471:    * shorter than the byte array. For more decoding control, use
 472:    * {@link java.nio.charset.CharsetDecoder}.  The behavior is not specified
 473:    * if the decoder encounters invalid characters; this implementation throws
 474:    * an Error.
 475:    *
 476:    * @param data byte array to copy
 477:    * @throws NullPointerException if data is null
 478:    * @throws Error if the decoding fails
 479:    * @see #String(byte[], int, int)
 480:    * @see #String(byte[], int, int, String)
 481:    * @since 1.1
 482:    */
 483:   public String(byte[] data)
 484:   {
 485:     this(data, 0, data.length);
 486:   }
 487: 
 488:   /**
 489:    * Creates a new String using the character sequence represented by
 490:    * the StringBuffer. Subsequent changes to buf do not affect the String.
 491:    *
 492:    * @param buffer StringBuffer to copy
 493:    * @throws NullPointerException if buffer is null
 494:    */
 495:   public String(StringBuffer buffer)
 496:   {
 497:     synchronized (buffer)
 498:       {
 499:         offset = 0;
 500:         count = buffer.count;
 501:         // Share unless buffer is 3/4 empty.
 502:         if ((count << 2) < buffer.value.length)
 503:           {
 504:             value = new char[count];
 505:             VMSystem.arraycopy(buffer.value, 0, value, 0, count);
 506:           }
 507:         else
 508:           {
 509:             buffer.shared = true;
 510:             value = buffer.value;
 511:           }
 512:       }
 513:   }
 514: 
 515:   /**
 516:    * Creates a new String using the character sequence represented by
 517:    * the StringBuilder. Subsequent changes to buf do not affect the String.
 518:    *
 519:    * @param buffer StringBuilder to copy
 520:    * @throws NullPointerException if buffer is null
 521:    */
 522:   public String(StringBuilder buffer)
 523:   {
 524:     this(buffer.value, 0, buffer.count);
 525:   }
 526: 
 527:   /**
 528:    * Special constructor which can share an array when safe to do so.
 529:    *
 530:    * @param data the characters to copy
 531:    * @param offset the location to start from
 532:    * @param count the number of characters to use
 533:    * @param dont_copy true if the array is trusted, and need not be copied
 534:    * @throws NullPointerException if chars is null
 535:    * @throws StringIndexOutOfBoundsException if bounds check fails
 536:    */
 537:   String(char[] data, int offset, int count, boolean dont_copy)
 538:   {
 539:     if (offset < 0)
 540:       throw new StringIndexOutOfBoundsException("offset: " + offset);
 541:     if (count < 0)
 542:       throw new StringIndexOutOfBoundsException("count: " + count);
 543:     // equivalent to: offset + count < 0 || offset + count > data.length
 544:     if (data.length - offset < count)
 545:       throw new StringIndexOutOfBoundsException("offset + count: "
 546:                         + (offset + count));
 547:     if (dont_copy)
 548:       {
 549:         value = data;
 550:         this.offset = offset;
 551:       }
 552:     else
 553:       {
 554:         value = new char[count];
 555:         VMSystem.arraycopy(data, offset, value, 0, count);
 556:         this.offset = 0;
 557:       }
 558:     this.count = count;
 559:   }
 560: 
 561:   /**
 562:    * Creates a new String containing the characters represented in the
 563:    * given subarray of Unicode code points.
 564:    * @param codePoints the entire array of code points
 565:    * @param offset the start of the subarray
 566:    * @param count the length of the subarray
 567:    * 
 568:    * @throws IllegalArgumentException if an invalid code point is found
 569:    * in the codePoints array
 570:    * @throws IndexOutOfBoundsException if offset is negative or offset + count
 571:    * is greater than the length of the array.
 572:    */
 573:   public String(int[] codePoints, int offset, int count)
 574:   {
 575:     // FIXME: This implementation appears to give correct internal
 576:     // representation of the String because: 
 577:     //   - length() is correct
 578:     //   - getting a char[] from toCharArray() and testing 
 579:     //     Character.codePointAt() on all the characters in that array gives
 580:     //     the appropriate results
 581:     // however printing the String gives incorrect results.  This may be 
 582:     // due to printing method errors (such as incorrectly looping through
 583:     // the String one char at a time rather than one "character" at a time.
 584:     
 585:     if (offset < 0)
 586:       throw new IndexOutOfBoundsException();
 587:     int end = offset + count;
 588:     int pos = 0;
 589:     // This creates a char array that is long enough for all of the code
 590:     // points to represent supplementary characters.  This is more than likely
 591:     // a waste of storage, so we use it only temporarily and then copy the 
 592:     // used portion into the value array.
 593:     char[] temp = new char[2 * codePoints.length];
 594:     for (int i = offset; i < end; i++)
 595:       {
 596:         pos += Character.toChars(codePoints[i], temp, pos);        
 597:       }
 598:     this.count = pos;
 599:     this.value = new char[pos];
 600:     System.arraycopy(temp, 0, value, 0, pos);
 601:     this.offset = 0;
 602:   }
 603:   
 604:   /**
 605:    * Returns the number of characters contained in this String.
 606:    *
 607:    * @return the length of this String
 608:    */
 609:   public int length()
 610:   {
 611:     return count;
 612:   }
 613: 
 614:   /**
 615:    * Returns the character located at the specified index within this String.
 616:    *
 617:    * @param index position of character to return (base 0)
 618:    * @return character located at position index
 619:    * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= length()
 620:    *         (while unspecified, this is a StringIndexOutOfBoundsException)
 621:    */
 622:   public char charAt(int index)
 623:   {
 624:     if (index < 0 || index >= count)
 625:       throw new StringIndexOutOfBoundsException(index);
 626:     return value[offset + index];
 627:   }
 628: 
 629:   /**
 630:    * Get the code point at the specified index.  This is like #charAt(int),
 631:    * but if the character is the start of a surrogate pair, and the
 632:    * following character completes the pair, then the corresponding
 633:    * supplementary code point is returned.
 634:    * @param index the index of the codepoint to get, starting at 0
 635:    * @return the codepoint at the specified index
 636:    * @throws IndexOutOfBoundsException if index is negative or &gt;= length()
 637:    * @since 1.5
 638:    */
 639:   public synchronized int codePointAt(int index)
 640:   {
 641:     // Use the CharSequence overload as we get better range checking
 642:     // this way.
 643:     return Character.codePointAt(this, index);
 644:   }
 645: 
 646:   /**
 647:    * Get the code point before the specified index.  This is like
 648:    * #codePointAt(int), but checks the characters at <code>index-1</code> and
 649:    * <code>index-2</code> to see if they form a supplementary code point.
 650:    * @param index the index just past the codepoint to get, starting at 0
 651:    * @return the codepoint at the specified index
 652:    * @throws IndexOutOfBoundsException if index is negative or &gt;= length()
 653:    *         (while unspecified, this is a StringIndexOutOfBoundsException)
 654:    * @since 1.5
 655:    */
 656:   public synchronized int codePointBefore(int index)
 657:   {
 658:     // Use the CharSequence overload as we get better range checking
 659:     // this way.
 660:     return Character.codePointBefore(this, index);
 661:   }
 662: 
 663:   /**
 664:    * Copies characters from this String starting at a specified start index,
 665:    * ending at a specified stop index, to a character array starting at
 666:    * a specified destination begin index.
 667:    *
 668:    * @param srcBegin index to begin copying characters from this String
 669:    * @param srcEnd index after the last character to be copied from this String
 670:    * @param dst character array which this String is copied into
 671:    * @param dstBegin index to start writing characters into dst
 672:    * @throws NullPointerException if dst is null
 673:    * @throws IndexOutOfBoundsException if any indices are out of bounds
 674:    *         (while unspecified, source problems cause a
 675:    *         StringIndexOutOfBoundsException, and dst problems cause an
 676:    *         ArrayIndexOutOfBoundsException)
 677:    */
 678:   public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)
 679:   {
 680:     if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count)
 681:       throw new StringIndexOutOfBoundsException();
 682:     VMSystem.arraycopy(value, srcBegin + offset,
 683:                      dst, dstBegin, srcEnd - srcBegin);
 684:   }
 685: 
 686:   /**
 687:    * Copies the low byte of each character from this String starting at a
 688:    * specified start index, ending at a specified stop index, to a byte array
 689:    * starting at a specified destination begin index.
 690:    *
 691:    * @param srcBegin index to being copying characters from this String
 692:    * @param srcEnd index after the last character to be copied from this String
 693:    * @param dst byte array which each low byte of this String is copied into
 694:    * @param dstBegin index to start writing characters into dst
 695:    * @throws NullPointerException if dst is null and copy length is non-zero
 696:    * @throws IndexOutOfBoundsException if any indices are out of bounds
 697:    *         (while unspecified, source problems cause a
 698:    *         StringIndexOutOfBoundsException, and dst problems cause an
 699:    *         ArrayIndexOutOfBoundsException)
 700:    * @see #getBytes()
 701:    * @see #getBytes(String)
 702:    * @deprecated use {@link #getBytes()}, which uses a char to byte encoder
 703:    */
 704:   public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin)
 705:   {
 706:     if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count)
 707:       throw new StringIndexOutOfBoundsException();
 708:     int i = srcEnd - srcBegin;
 709:     srcBegin += offset;
 710:     while (--i >= 0)
 711:       dst[dstBegin++] = (byte) value[srcBegin++];
 712:   }
 713: 
 714:   /**
 715:    * Converts the Unicode characters in this String to a byte array. Uses the
 716:    * specified encoding method, so the result may be longer or shorter than
 717:    * the String. For more encoding control, use
 718:    * {@link java.nio.charset.CharsetEncoder}, and for valid character sets,
 719:    * see {@link java.nio.charset.Charset}. Unsupported characters get
 720:    * replaced by an encoding specific byte.
 721:    *
 722:    * @param enc encoding name
 723:    * @return the resulting byte array
 724:    * @throws NullPointerException if enc is null
 725:    * @throws UnsupportedEncodingException if encoding is not supported
 726:    * @since 1.1
 727:    */
 728:   public byte[] getBytes(String enc) throws UnsupportedEncodingException
 729:   {
 730:     try 
 731:       {
 732:     CharsetEncoder cse = Charset.forName(enc).newEncoder();
 733:     cse.onMalformedInput(CodingErrorAction.REPLACE);
 734:     cse.onUnmappableCharacter(CodingErrorAction.REPLACE);
 735:     ByteBuffer bbuf = cse.encode(CharBuffer.wrap(value, offset, count));
 736:     if(bbuf.hasArray())
 737:       return bbuf.array();
 738:     
 739:     // Doubt this will happen. But just in case.
 740:     byte[] bytes = new byte[bbuf.remaining()];
 741:     bbuf.get(bytes);
 742:     return bytes;
 743:       } 
 744:     catch(IllegalCharsetNameException e)
 745:       {
 746:     throw new UnsupportedEncodingException("Encoding: " + enc
 747:                            + " not found.");
 748:       } 
 749:     catch(UnsupportedCharsetException e)
 750:       {
 751:     throw new UnsupportedEncodingException("Encoding: " + enc
 752:                            + " not found.");
 753:       } 
 754:     catch(CharacterCodingException e)
 755:       {
 756:     // This shouldn't ever happen.
 757:     throw (InternalError) new InternalError().initCause(e);
 758:       }      
 759:   }
 760: 
 761:   /**
 762:    * Converts the Unicode characters in this String to a byte array. Uses the
 763:    * encoding of the platform's default charset, so the result may be longer
 764:    * or shorter than the String. For more encoding control, use
 765:    * {@link java.nio.charset.CharsetEncoder}. Unsupported characters get
 766:    * replaced by an encoding specific byte.
 767:    *
 768:    * @return the resulting byte array, or null on a problem
 769:    * @since 1.1
 770:    */
 771:   public byte[] getBytes()
 772:   { 
 773:       try 
 774:       {
 775:           return getBytes(System.getProperty("file.encoding"));
 776:       } catch(Exception e) {
 777:           // XXX - Throw an error here? 
 778:           // For now, default to the 'safe' encoding.
 779:           byte[] bytes = new byte[count];
 780:           for(int i=0;i<count;i++)
 781:           bytes[i] = (byte)((value[offset+i] <= 0xFF)?
 782:                     value[offset+i]:'?');
 783:           return bytes;
 784:       }
 785:   }
 786: 
 787:   /**
 788:    * Predicate which compares anObject to this. This is true only for Strings
 789:    * with the same character sequence.
 790:    *
 791:    * @param anObject the object to compare
 792:    * @return true if anObject is semantically equal to this
 793:    * @see #compareTo(String)
 794:    * @see #equalsIgnoreCase(String)
 795:    */
 796:   public boolean equals(Object anObject)
 797:   {
 798:     if (! (anObject instanceof String))
 799:       return false;
 800:     String str2 = (String) anObject;
 801:     if (count != str2.count)
 802:       return false;
 803:     if (value == str2.value && offset == str2.offset)
 804:       return true;
 805:     int i = count;
 806:     int x = offset;
 807:     int y = str2.offset;
 808:     while (--i >= 0)
 809:       if (value[x++] != str2.value[y++])
 810:         return false;
 811:     return true;
 812:   }
 813: 
 814:   /**
 815:    * Compares the given StringBuffer to this String. This is true if the
 816:    * StringBuffer has the same content as this String at this moment.
 817:    *
 818:    * @param buffer the StringBuffer to compare to
 819:    * @return true if StringBuffer has the same character sequence
 820:    * @throws NullPointerException if the given StringBuffer is null
 821:    * @since 1.4
 822:    */
 823:   public boolean contentEquals(StringBuffer buffer)
 824:   {
 825:     synchronized (buffer)
 826:       {
 827:         if (count != buffer.count)
 828:           return false;
 829:         if (value == buffer.value)
 830:           return true; // Possible if shared.
 831:         int i = count;
 832:         int x = offset + count;
 833:         while (--i >= 0)
 834:           if (value[--x] != buffer.value[i])
 835:             return false;
 836:         return true;
 837:       }
 838:   }