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