1 /* 2 * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved 28 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved 29 * 30 * The original version of this source code and documentation is copyrighted 31 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These 32 * materials are provided under terms of a License Agreement between Taligent 33 * and Sun. This technology is protected by multiple US and International 34 * patents. This notice and attribution to Taligent may not be removed. 35 * Taligent is a registered trademark of Taligent, Inc. 36 * 37 */ 38 39 package java.text; 40 41 import java.io.IOException; 42 import java.io.ObjectInputStream; 43 import java.io.Serializable; 44 import java.text.spi.DecimalFormatSymbolsProvider; 45 import java.util.Currency; 46 import java.util.Locale; 47 import sun.util.locale.provider.CalendarDataUtility; 48 import sun.util.locale.provider.LocaleProviderAdapter; 49 import sun.util.locale.provider.LocaleServiceProviderPool; 50 import sun.util.locale.provider.ResourceBundleBasedAdapter; 51 52 /** 53 * This class represents the set of symbols (such as the decimal separator, 54 * the grouping separator, and so on) needed by <code>DecimalFormat</code> 55 * to format numbers. <code>DecimalFormat</code> creates for itself an instance of 56 * <code>DecimalFormatSymbols</code> from its locale data. If you need to change any 57 * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from 58 * your <code>DecimalFormat</code> and modify it. 59 * 60 * <p>If the locale contains "rg" (region override) 61 * <a href="../util/Locale.html#def_locale_extension">Unicode extension</a>, 62 * the symbols are overriden for the designated region. 63 * 64 * @see java.util.Locale 65 * @see DecimalFormat 66 * @author Mark Davis 67 * @author Alan Liu 68 * @since 1.1 69 */ 70 71 public class DecimalFormatSymbols implements Cloneable, Serializable { 72 73 /** 74 * Create a DecimalFormatSymbols object for the default 75 * {@link java.util.Locale.Category#FORMAT FORMAT} locale. 76 * This constructor can only construct instances for the locales 77 * supported by the Java runtime environment, not for those 78 * supported by installed 79 * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider} 80 * implementations. For full locale coverage, use the 81 * {@link #getInstance(Locale) getInstance} method. 82 * <p>This is equivalent to calling 83 * {@link #DecimalFormatSymbols(Locale) 84 * DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT))}. 85 * @see java.util.Locale#getDefault(java.util.Locale.Category) 86 * @see java.util.Locale.Category#FORMAT 87 */ 88 public DecimalFormatSymbols() { 89 initialize( Locale.getDefault(Locale.Category.FORMAT) ); 90 } 91 92 /** 93 * Create a DecimalFormatSymbols object for the given locale. 94 * This constructor can only construct instances for the locales 95 * supported by the Java runtime environment, not for those 96 * supported by installed 97 * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider} 98 * implementations. For full locale coverage, use the 99 * {@link #getInstance(Locale) getInstance} method. 100 * If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION} 101 * for the numbering system, the instance is initialized with the specified numbering 102 * system if the JRE implementation supports it. For example, 103 * <pre> 104 * NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai")) 105 * </pre> 106 * This may return a {@code NumberFormat} instance with the Thai numbering system, 107 * instead of the Latin numbering system. 108 * 109 * @param locale the desired locale 110 * @exception NullPointerException if <code>locale</code> is null 111 */ 112 public DecimalFormatSymbols( Locale locale ) { 113 initialize( locale ); 114 } 115 116 /** 117 * Returns an array of all locales for which the 118 * <code>getInstance</code> methods of this class can return 119 * localized instances. 120 * The returned array represents the union of locales supported by the Java 121 * runtime and by installed 122 * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider} 123 * implementations. It must contain at least a <code>Locale</code> 124 * instance equal to {@link java.util.Locale#US Locale.US}. 125 * 126 * @return an array of locales for which localized 127 * <code>DecimalFormatSymbols</code> instances are available. 128 * @since 1.6 129 */ 130 public static Locale[] getAvailableLocales() { 131 LocaleServiceProviderPool pool = 132 LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class); 133 return pool.getAvailableLocales(); 134 } 135 136 /** 137 * Gets the <code>DecimalFormatSymbols</code> instance for the default 138 * locale. This method provides access to <code>DecimalFormatSymbols</code> 139 * instances for locales supported by the Java runtime itself as well 140 * as for those supported by installed 141 * {@link java.text.spi.DecimalFormatSymbolsProvider 142 * DecimalFormatSymbolsProvider} implementations. 143 * <p>This is equivalent to calling 144 * {@link #getInstance(Locale) 145 * getInstance(Locale.getDefault(Locale.Category.FORMAT))}. 146 * @see java.util.Locale#getDefault(java.util.Locale.Category) 147 * @see java.util.Locale.Category#FORMAT 148 * @return a <code>DecimalFormatSymbols</code> instance. 149 * @since 1.6 150 */ 151 public static final DecimalFormatSymbols getInstance() { 152 return getInstance(Locale.getDefault(Locale.Category.FORMAT)); 153 } 154 155 /** 156 * Gets the <code>DecimalFormatSymbols</code> instance for the specified 157 * locale. This method provides access to <code>DecimalFormatSymbols</code> 158 * instances for locales supported by the Java runtime itself as well 159 * as for those supported by installed 160 * {@link java.text.spi.DecimalFormatSymbolsProvider 161 * DecimalFormatSymbolsProvider} implementations. 162 * If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION} 163 * for the numbering system, the instance is initialized with the specified numbering 164 * system if the JRE implementation supports it. For example, 165 * <pre> 166 * NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai")) 167 * </pre> 168 * This may return a {@code NumberFormat} instance with the Thai numbering system, 169 * instead of the Latin numbering system. 170 * 171 * @param locale the desired locale. 172 * @return a <code>DecimalFormatSymbols</code> instance. 173 * @exception NullPointerException if <code>locale</code> is null 174 * @since 1.6 175 */ 176 public static final DecimalFormatSymbols getInstance(Locale locale) { 177 LocaleProviderAdapter adapter; 178 adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale); 179 DecimalFormatSymbolsProvider provider = adapter.getDecimalFormatSymbolsProvider(); 180 DecimalFormatSymbols dfsyms = provider.getInstance(locale); 181 if (dfsyms == null) { 182 provider = LocaleProviderAdapter.forJRE().getDecimalFormatSymbolsProvider(); 183 dfsyms = provider.getInstance(locale); 184 } 185 return dfsyms; 186 } 187 188 /** 189 * Gets the character used for zero. Different for Arabic, etc. 190 * 191 * @return the character used for zero 192 */ 193 public char getZeroDigit() { 194 return zeroDigit; 195 } 196 197 /** 198 * Sets the character used for zero. Different for Arabic, etc. 199 * 200 * @param zeroDigit the character used for zero 201 */ 202 public void setZeroDigit(char zeroDigit) { 203 this.zeroDigit = zeroDigit; 204 } 205 206 /** 207 * Gets the character used for thousands separator. Different for French, etc. 208 * 209 * @return the grouping separator 210 */ 211 public char getGroupingSeparator() { 212 return groupingSeparator; 213 } 214 215 /** 216 * Sets the character used for thousands separator. Different for French, etc. 217 * 218 * @param groupingSeparator the grouping separator 219 */ 220 public void setGroupingSeparator(char groupingSeparator) { 221 this.groupingSeparator = groupingSeparator; 222 } 223 224 /** 225 * Gets the character used for decimal sign. Different for French, etc. 226 * 227 * @return the character used for decimal sign 228 */ 229 public char getDecimalSeparator() { 230 return decimalSeparator; 231 } 232 233 /** 234 * Sets the character used for decimal sign. Different for French, etc. 235 * 236 * @param decimalSeparator the character used for decimal sign 237 */ 238 public void setDecimalSeparator(char decimalSeparator) { 239 this.decimalSeparator = decimalSeparator; 240 } 241 242 /** 243 * Gets the character used for per mille sign. Different for Arabic, etc. 244 * 245 * @return the character used for per mille sign 246 */ 247 public char getPerMill() { 248 return perMill; 249 } 250 251 /** 252 * Sets the character used for per mille sign. Different for Arabic, etc. 253 * 254 * @param perMill the character used for per mille sign 255 */ 256 public void setPerMill(char perMill) { 257 this.perMill = perMill; 258 } 259 260 /** 261 * Gets the character used for percent sign. Different for Arabic, etc. 262 * 263 * @return the character used for percent sign 264 */ 265 public char getPercent() { 266 return percent; 267 } 268 269 /** 270 * Sets the character used for percent sign. Different for Arabic, etc. 271 * 272 * @param percent the character used for percent sign 273 */ 274 public void setPercent(char percent) { 275 this.percent = percent; 276 } 277 278 /** 279 * Gets the character used for a digit in a pattern. 280 * 281 * @return the character used for a digit in a pattern 282 */ 283 public char getDigit() { 284 return digit; 285 } 286 287 /** 288 * Sets the character used for a digit in a pattern. 289 * 290 * @param digit the character used for a digit in a pattern 291 */ 292 public void setDigit(char digit) { 293 this.digit = digit; 294 } 295 296 /** 297 * Gets the character used to separate positive and negative subpatterns 298 * in a pattern. 299 * 300 * @return the pattern separator 301 */ 302 public char getPatternSeparator() { 303 return patternSeparator; 304 } 305 306 /** 307 * Sets the character used to separate positive and negative subpatterns 308 * in a pattern. 309 * 310 * @param patternSeparator the pattern separator 311 */ 312 public void setPatternSeparator(char patternSeparator) { 313 this.patternSeparator = patternSeparator; 314 } 315 316 /** 317 * Gets the string used to represent infinity. Almost always left 318 * unchanged. 319 * 320 * @return the string representing infinity 321 */ 322 public String getInfinity() { 323 return infinity; 324 } 325 326 /** 327 * Sets the string used to represent infinity. Almost always left 328 * unchanged. 329 * 330 * @param infinity the string representing infinity 331 */ 332 public void setInfinity(String infinity) { 333 this.infinity = infinity; 334 } 335 336 /** 337 * Gets the string used to represent "not a number". Almost always left 338 * unchanged. 339 * 340 * @return the string representing "not a number" 341 */ 342 public String getNaN() { 343 return NaN; 344 } 345 346 /** 347 * Sets the string used to represent "not a number". Almost always left 348 * unchanged. 349 * 350 * @param NaN the string representing "not a number" 351 */ 352 public void setNaN(String NaN) { 353 this.NaN = NaN; 354 } 355 356 /** 357 * Gets the character used to represent minus sign. If no explicit 358 * negative format is specified, one is formed by prefixing 359 * minusSign to the positive format. 360 * 361 * @return the character representing minus sign 362 */ 363 public char getMinusSign() { 364 return minusSign; 365 } 366 367 /** 368 * Sets the character used to represent minus sign. If no explicit 369 * negative format is specified, one is formed by prefixing 370 * minusSign to the positive format. 371 * 372 * @param minusSign the character representing minus sign 373 */ 374 public void setMinusSign(char minusSign) { 375 this.minusSign = minusSign; 376 } 377 378 /** 379 * Returns the currency symbol for the currency of these 380 * DecimalFormatSymbols in their locale. 381 * 382 * @return the currency symbol 383 * @since 1.2 384 */ 385 public String getCurrencySymbol() 386 { 387 initializeCurrency(locale); 388 return currencySymbol; 389 } 390 391 /** 392 * Sets the currency symbol for the currency of these 393 * DecimalFormatSymbols in their locale. 394 * 395 * @param currency the currency symbol 396 * @since 1.2 397 */ 398 public void setCurrencySymbol(String currency) 399 { 400 initializeCurrency(locale); 401 currencySymbol = currency; 402 } 403 404 /** 405 * Returns the ISO 4217 currency code of the currency of these 406 * DecimalFormatSymbols. 407 * 408 * @return the currency code 409 * @since 1.2 410 */ 411 public String getInternationalCurrencySymbol() 412 { 413 initializeCurrency(locale); 414 return intlCurrencySymbol; 415 } 416 417 /** 418 * Sets the ISO 4217 currency code of the currency of these 419 * DecimalFormatSymbols. 420 * If the currency code is valid (as defined by 421 * {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}), 422 * this also sets the currency attribute to the corresponding Currency 423 * instance and the currency symbol attribute to the currency's symbol 424 * in the DecimalFormatSymbols' locale. If the currency code is not valid, 425 * then the currency attribute is set to null and the currency symbol 426 * attribute is not modified. 427 * 428 * @param currencyCode the currency code 429 * @see #setCurrency 430 * @see #setCurrencySymbol 431 * @since 1.2 432 */ 433 public void setInternationalCurrencySymbol(String currencyCode) 434 { 435 initializeCurrency(locale); 436 intlCurrencySymbol = currencyCode; 437 currency = null; 438 if (currencyCode != null) { 439 try { 440 currency = Currency.getInstance(currencyCode); 441 currencySymbol = currency.getSymbol(); 442 } catch (IllegalArgumentException e) { 443 } 444 } 445 } 446 447 /** 448 * Gets the currency of these DecimalFormatSymbols. May be null if the 449 * currency symbol attribute was previously set to a value that's not 450 * a valid ISO 4217 currency code. 451 * 452 * @return the currency used, or null 453 * @since 1.4 454 */ 455 public Currency getCurrency() { 456 initializeCurrency(locale); 457 return currency; 458 } 459 460 /** 461 * Sets the currency of these DecimalFormatSymbols. 462 * This also sets the currency symbol attribute to the currency's symbol 463 * in the DecimalFormatSymbols' locale, and the international currency 464 * symbol attribute to the currency's ISO 4217 currency code. 465 * 466 * @param currency the new currency to be used 467 * @exception NullPointerException if <code>currency</code> is null 468 * @since 1.4 469 * @see #setCurrencySymbol 470 * @see #setInternationalCurrencySymbol 471 */ 472 public void setCurrency(Currency currency) { 473 if (currency == null) { 474 throw new NullPointerException(); 475 } 476 initializeCurrency(locale); 477 this.currency = currency; 478 intlCurrencySymbol = currency.getCurrencyCode(); 479 currencySymbol = currency.getSymbol(locale); 480 } 481 482 483 /** 484 * Returns the monetary decimal separator. 485 * 486 * @return the monetary decimal separator 487 * @since 1.2 488 */ 489 public char getMonetaryDecimalSeparator() 490 { 491 return monetarySeparator; 492 } 493 494 /** 495 * Sets the monetary decimal separator. 496 * 497 * @param sep the monetary decimal separator 498 * @since 1.2 499 */ 500 public void setMonetaryDecimalSeparator(char sep) 501 { 502 monetarySeparator = sep; 503 } 504 505 //------------------------------------------------------------ 506 // BEGIN Package Private methods ... to be made public later 507 //------------------------------------------------------------ 508 509 /** 510 * Returns the character used to separate the mantissa from the exponent. 511 */ 512 char getExponentialSymbol() 513 { 514 return exponential; 515 } 516 517 /** 518 * Returns the string used to separate the mantissa from the exponent. 519 * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. 520 * 521 * @return the exponent separator string 522 * @see #setExponentSeparator(java.lang.String) 523 * @since 1.6 524 */ 525 public String getExponentSeparator() 526 { 527 return exponentialSeparator; 528 } 529 530 /** 531 * Sets the character used to separate the mantissa from the exponent. 532 */ 533 void setExponentialSymbol(char exp) 534 { 535 exponential = exp; 536 } 537 538 /** 539 * Sets the string used to separate the mantissa from the exponent. 540 * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. 541 * 542 * @param exp the exponent separator string 543 * @exception NullPointerException if <code>exp</code> is null 544 * @see #getExponentSeparator() 545 * @since 1.6 546 */ 547 public void setExponentSeparator(String exp) 548 { 549 if (exp == null) { 550 throw new NullPointerException(); 551 } 552 exponentialSeparator = exp; 553 } 554 555 556 //------------------------------------------------------------ 557 // END Package Private methods ... to be made public later 558 //------------------------------------------------------------ 559 560 /** 561 * Standard override. 562 */ 563 @Override 564 public Object clone() { 565 try { 566 return (DecimalFormatSymbols)super.clone(); 567 // other fields are bit-copied 568 } catch (CloneNotSupportedException e) { 569 throw new InternalError(e); 570 } 571 } 572 573 /** 574 * Override equals. 575 */ 576 @Override 577 public boolean equals(Object obj) { 578 if (obj == null) return false; 579 if (this == obj) return true; 580 if (getClass() != obj.getClass()) return false; 581 DecimalFormatSymbols other = (DecimalFormatSymbols) obj; 582 return (zeroDigit == other.zeroDigit && 583 groupingSeparator == other.groupingSeparator && 584 decimalSeparator == other.decimalSeparator && 585 percent == other.percent && 586 perMill == other.perMill && 587 digit == other.digit && 588 minusSign == other.minusSign && 589 patternSeparator == other.patternSeparator && 590 infinity.equals(other.infinity) && 591 NaN.equals(other.NaN) && 592 getCurrencySymbol().equals(other.getCurrencySymbol()) && // possible currency init occurs here 593 intlCurrencySymbol.equals(other.intlCurrencySymbol) && 594 currency == other.currency && 595 monetarySeparator == other.monetarySeparator && 596 exponentialSeparator.equals(other.exponentialSeparator) && 597 locale.equals(other.locale)); 598 } 599 600 /** 601 * Override hashCode. 602 */ 603 @Override 604 public int hashCode() { 605 int result = zeroDigit; 606 result = result * 37 + groupingSeparator; 607 result = result * 37 + decimalSeparator; 608 return result; 609 } 610 611 /** 612 * Initializes the symbols from the FormatData resource bundle. 613 */ 614 private void initialize( Locale locale ) { 615 this.locale = locale; 616 617 // check for region override 618 Locale override = locale.getUnicodeLocaleType("nu") == null ? 619 CalendarDataUtility.findRegionOverride(locale).orElse(locale) : 620 locale; 621 622 // get resource bundle data 623 LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, override); 624 // Avoid potential recursions 625 if (!(adapter instanceof ResourceBundleBasedAdapter)) { 626 adapter = LocaleProviderAdapter.getResourceBundleBased(); 627 } 628 Object[] data = adapter.getLocaleResources(override).getDecimalFormatSymbolsData(); 629 String[] numberElements = (String[]) data[0]; 630 631 decimalSeparator = numberElements[0].charAt(0); 632 groupingSeparator = numberElements[1].charAt(0); 633 patternSeparator = numberElements[2].charAt(0); 634 percent = numberElements[3].charAt(0); 635 zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc. 636 digit = numberElements[5].charAt(0); 637 minusSign = numberElements[6].charAt(0); 638 exponential = numberElements[7].charAt(0); 639 exponentialSeparator = numberElements[7]; //string representation new since 1.6 640 perMill = numberElements[8].charAt(0); 641 infinity = numberElements[9]; 642 NaN = numberElements[10]; 643 644 // maybe filled with previously cached values, or null. 645 intlCurrencySymbol = (String) data[1]; 646 currencySymbol = (String) data[2]; 647 648 // Currently the monetary decimal separator is the same as the 649 // standard decimal separator for all locales that we support. 650 // If that changes, add a new entry to NumberElements. 651 monetarySeparator = decimalSeparator; 652 } 653 654 /** 655 * Lazy initialization for currency related fields 656 */ 657 private void initializeCurrency(Locale locale) { 658 if (currencyInitialized) { 659 return; 660 } 661 662 // Try to obtain the currency used in the locale's country. 663 // Check for empty country string separately because it's a valid 664 // country ID for Locale (and used for the C locale), but not a valid 665 // ISO 3166 country code, and exceptions are expensive. 666 if (locale.getCountry().length() > 0) { 667 try { 668 currency = Currency.getInstance(locale); 669 } catch (IllegalArgumentException e) { 670 // use default values below for compatibility 671 } 672 } 673 674 if (currency != null) { 675 // get resource bundle data 676 LocaleProviderAdapter adapter = 677 LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale); 678 // Avoid potential recursions 679 if (!(adapter instanceof ResourceBundleBasedAdapter)) { 680 adapter = LocaleProviderAdapter.getResourceBundleBased(); 681 } 682 Object[] data = adapter.getLocaleResources(locale).getDecimalFormatSymbolsData(); 683 intlCurrencySymbol = currency.getCurrencyCode(); 684 if (data[1] != null && data[1] == intlCurrencySymbol) { 685 currencySymbol = (String) data[2]; 686 } else { 687 currencySymbol = currency.getSymbol(locale); 688 data[1] = intlCurrencySymbol; 689 data[2] = currencySymbol; 690 } 691 } else { 692 // default values 693 intlCurrencySymbol = "XXX"; 694 try { 695 currency = Currency.getInstance(intlCurrencySymbol); 696 } catch (IllegalArgumentException e) { 697 } 698 currencySymbol = "\u00A4"; 699 } 700 701 currencyInitialized = true; 702 } 703 704 /** 705 * Reads the default serializable fields, provides default values for objects 706 * in older serial versions, and initializes non-serializable fields. 707 * If <code>serialVersionOnStream</code> 708 * is less than 1, initializes <code>monetarySeparator</code> to be 709 * the same as <code>decimalSeparator</code> and <code>exponential</code> 710 * to be 'E'. 711 * If <code>serialVersionOnStream</code> is less than 2, 712 * initializes <code>locale</code>to the root locale, and initializes 713 * If <code>serialVersionOnStream</code> is less than 3, it initializes 714 * <code>exponentialSeparator</code> using <code>exponential</code>. 715 * Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that 716 * default serialization will work properly if this object is streamed out again. 717 * Initializes the currency from the intlCurrencySymbol field. 718 * 719 * @since 1.1.6 720 */ 721 private void readObject(ObjectInputStream stream) 722 throws IOException, ClassNotFoundException { 723 stream.defaultReadObject(); 724 if (serialVersionOnStream < 1) { 725 // Didn't have monetarySeparator or exponential field; 726 // use defaults. 727 monetarySeparator = decimalSeparator; 728 exponential = 'E'; 729 } 730 if (serialVersionOnStream < 2) { 731 // didn't have locale; use root locale 732 locale = Locale.ROOT; 733 } 734 if (serialVersionOnStream < 3) { 735 // didn't have exponentialSeparator. Create one using exponential 736 exponentialSeparator = Character.toString(exponential); 737 } 738 serialVersionOnStream = currentSerialVersion; 739 740 if (intlCurrencySymbol != null) { 741 try { 742 currency = Currency.getInstance(intlCurrencySymbol); 743 } catch (IllegalArgumentException e) { 744 } 745 currencyInitialized = true; 746 } 747 } 748 749 /** 750 * Character used for zero. 751 * 752 * @serial 753 * @see #getZeroDigit 754 */ 755 private char zeroDigit; 756 757 /** 758 * Character used for thousands separator. 759 * 760 * @serial 761 * @see #getGroupingSeparator 762 */ 763 private char groupingSeparator; 764 765 /** 766 * Character used for decimal sign. 767 * 768 * @serial 769 * @see #getDecimalSeparator 770 */ 771 private char decimalSeparator; 772 773 /** 774 * Character used for per mille sign. 775 * 776 * @serial 777 * @see #getPerMill 778 */ 779 private char perMill; 780 781 /** 782 * Character used for percent sign. 783 * @serial 784 * @see #getPercent 785 */ 786 private char percent; 787 788 /** 789 * Character used for a digit in a pattern. 790 * 791 * @serial 792 * @see #getDigit 793 */ 794 private char digit; 795 796 /** 797 * Character used to separate positive and negative subpatterns 798 * in a pattern. 799 * 800 * @serial 801 * @see #getPatternSeparator 802 */ 803 private char patternSeparator; 804 805 /** 806 * String used to represent infinity. 807 * @serial 808 * @see #getInfinity 809 */ 810 private String infinity; 811 812 /** 813 * String used to represent "not a number". 814 * @serial 815 * @see #getNaN 816 */ 817 private String NaN; 818 819 /** 820 * Character used to represent minus sign. 821 * @serial 822 * @see #getMinusSign 823 */ 824 private char minusSign; 825 826 /** 827 * String denoting the local currency, e.g. "$". 828 * @serial 829 * @see #getCurrencySymbol 830 */ 831 private String currencySymbol; 832 833 /** 834 * ISO 4217 currency code denoting the local currency, e.g. "USD". 835 * @serial 836 * @see #getInternationalCurrencySymbol 837 */ 838 private String intlCurrencySymbol; 839 840 /** 841 * The decimal separator used when formatting currency values. 842 * @serial 843 * @since 1.1.6 844 * @see #getMonetaryDecimalSeparator 845 */ 846 private char monetarySeparator; // Field new in JDK 1.1.6 847 848 /** 849 * The character used to distinguish the exponent in a number formatted 850 * in exponential notation, e.g. 'E' for a number such as "1.23E45". 851 * <p> 852 * Note that the public API provides no way to set this field, 853 * even though it is supported by the implementation and the stream format. 854 * The intent is that this will be added to the API in the future. 855 * 856 * @serial 857 * @since 1.1.6 858 */ 859 private char exponential; // Field new in JDK 1.1.6 860 861 /** 862 * The string used to separate the mantissa from the exponent. 863 * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. 864 * <p> 865 * If both <code>exponential</code> and <code>exponentialSeparator</code> 866 * exist, this <code>exponentialSeparator</code> has the precedence. 867 * 868 * @serial 869 * @since 1.6 870 */ 871 private String exponentialSeparator; // Field new in JDK 1.6 872 873 /** 874 * The locale of these currency format symbols. 875 * 876 * @serial 877 * @since 1.4 878 */ 879 private Locale locale; 880 881 // currency; only the ISO code is serialized. 882 private transient Currency currency; 883 private transient volatile boolean currencyInitialized; 884 885 // Proclaim JDK 1.1 FCS compatibility 886 static final long serialVersionUID = 5772796243397350300L; 887 888 // The internal serial version which says which version was written 889 // - 0 (default) for version up to JDK 1.1.5 890 // - 1 for version from JDK 1.1.6, which includes two new fields: 891 // monetarySeparator and exponential. 892 // - 2 for version from J2SE 1.4, which includes locale field. 893 // - 3 for version from J2SE 1.6, which includes exponentialSeparator field. 894 private static final int currentSerialVersion = 3; 895 896 /** 897 * Describes the version of <code>DecimalFormatSymbols</code> present on the stream. 898 * Possible values are: 899 * <ul> 900 * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6. 901 * 902 * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include 903 * two new fields: <code>monetarySeparator</code> and <code>exponential</code>. 904 * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a 905 * new <code>locale</code> field. 906 * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a 907 * new <code>exponentialSeparator</code> field. 908 * </ul> 909 * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format 910 * (corresponding to the highest allowable <code>serialVersionOnStream</code>) 911 * is always written. 912 * 913 * @serial 914 * @since 1.1.6 915 */ 916 private int serialVersionOnStream = currentSerialVersion; 917 }