src/share/classes/java/text/DecimalFormatSymbols.java

Print this page
rev 5615 : 6336885: RFE: Locale Data Deployment Enhancements
4609153: Provide locale data for Indic locales
5104387: Support for gl_ES locale (galician language)
6337471: desktop/system locale preferences support
7056139: (cal) SPI support for locale-dependent Calendar parameters
7058206: Provide CalendarData SPI for week params and display field value names
7073852: Support multiple scripts for digits and decimal symbols per locale
7079560: [Fmt-Da] Context dependent month names support in SimpleDateFormat
7171324: getAvailableLocales() of locale sensitive services should return the actual availability of locales
7151414: (cal) Support calendar type identification
7168528: LocaleServiceProvider needs to be aware of Locale extensions
7171372: (cal) locale's default Calendar should be created if unknown calendar is specified
Summary: JEP 127: Improve Locale Data Packaging and Adopt Unicode CLDR Data (part 1 w/o Jigsaw. by Naoto Sato and Masayoshi Okutsu)
   1 /*
   2  * Copyright (c) 1996, 2010, 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


  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 java.util.ResourceBundle;
  48 import java.util.concurrent.ConcurrentHashMap;

  49 
  50 import sun.util.LocaleServiceProviderPool;
  51 import sun.util.resources.LocaleData;
  52 
  53 /**
  54  * This class represents the set of symbols (such as the decimal separator,
  55  * the grouping separator, and so on) needed by <code>DecimalFormat</code>
  56  * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
  57  * <code>DecimalFormatSymbols</code> from its locale data.  If you need to change any
  58  * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
  59  * your <code>DecimalFormat</code> and modify it.
  60  *
  61  * @see          java.util.Locale
  62  * @see          DecimalFormat
  63  * @author       Mark Davis
  64  * @author       Alan Liu
  65  */
  66 
  67 public class DecimalFormatSymbols implements Cloneable, Serializable {
  68 
  69     /**
  70      * Create a DecimalFormatSymbols object for the default locale.
  71      * This constructor can only construct instances for the locales
  72      * supported by the Java runtime environment, not for those
  73      * supported by installed
  74      * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
  75      * implementations. For full locale coverage, use the
  76      * {@link #getInstance(Locale) getInstance} method.
  77      */
  78     public DecimalFormatSymbols() {
  79         initialize( Locale.getDefault(Locale.Category.FORMAT) );
  80     }
  81 
  82     /**
  83      * Create a DecimalFormatSymbols object for the given locale.
  84      * This constructor can only construct instances for the locales
  85      * supported by the Java runtime environment, not for those
  86      * supported by installed
  87      * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
  88      * implementations. For full locale coverage, use the
  89      * {@link #getInstance(Locale) getInstance} method.








  90      *
  91      * @exception NullPointerException if <code>locale</code> is null
  92      */
  93     public DecimalFormatSymbols( Locale locale ) {
  94         initialize( locale );
  95     }
  96 
  97     /**
  98      * Returns an array of all locales for which the
  99      * <code>getInstance</code> methods of this class can return
 100      * localized instances.
 101      * The returned array represents the union of locales supported by the Java
 102      * runtime and by installed
 103      * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
 104      * implementations.  It must contain at least a <code>Locale</code>
 105      * instance equal to {@link java.util.Locale#US Locale.US}.
 106      *
 107      * @return An array of locales for which localized
 108      *         <code>DecimalFormatSymbols</code> instances are available.
 109      * @since 1.6


 118      * Gets the <code>DecimalFormatSymbols</code> instance for the default
 119      * locale.  This method provides access to <code>DecimalFormatSymbols</code>
 120      * instances for locales supported by the Java runtime itself as well
 121      * as for those supported by installed
 122      * {@link java.text.spi.DecimalFormatSymbolsProvider
 123      * DecimalFormatSymbolsProvider} implementations.
 124      * @return a <code>DecimalFormatSymbols</code> instance.
 125      * @since 1.6
 126      */
 127     public static final DecimalFormatSymbols getInstance() {
 128         return getInstance(Locale.getDefault(Locale.Category.FORMAT));
 129     }
 130 
 131     /**
 132      * Gets the <code>DecimalFormatSymbols</code> instance for the specified
 133      * locale.  This method provides access to <code>DecimalFormatSymbols</code>
 134      * instances for locales supported by the Java runtime itself as well
 135      * as for those supported by installed
 136      * {@link java.text.spi.DecimalFormatSymbolsProvider
 137      * DecimalFormatSymbolsProvider} implementations.








 138      * @param locale the desired locale.
 139      * @return a <code>DecimalFormatSymbols</code> instance.
 140      * @exception NullPointerException if <code>locale</code> is null
 141      * @since 1.6
 142      */
 143     public static final DecimalFormatSymbols getInstance(Locale locale) {
 144 
 145         // Check whether a provider can provide an implementation that's closer
 146         // to the requested locale than what the Java runtime itself can provide.
 147         LocaleServiceProviderPool pool =
 148             LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
 149         if (pool.hasProviders()) {
 150             DecimalFormatSymbols providersInstance = pool.getLocalizedObject(
 151                                 DecimalFormatSymbolsGetter.INSTANCE, locale);
 152             if (providersInstance != null) {
 153                 return providersInstance;
 154             }
 155         }
 156 
 157         return new DecimalFormatSymbols(locale);
 158     }
 159 
 160     /**
 161      * Gets the character used for zero. Different for Arabic, etc.
 162      */
 163     public char getZeroDigit() {
 164         return zeroDigit;
 165     }
 166 
 167     /**
 168      * Sets the character used for zero. Different for Arabic, etc.
 169      */
 170     public void setZeroDigit(char zeroDigit) {
 171         this.zeroDigit = zeroDigit;
 172     }
 173 
 174     /**
 175      * Gets the character used for thousands separator. Different for French, etc.
 176      */
 177     public char getGroupingSeparator() {
 178         return groupingSeparator;
 179     }


 457    * @exception NullPointerException if <code>exp</code> is null
 458    * @see #getExponentSeparator()
 459    * @since 1.6
 460    */
 461     public void setExponentSeparator(String exp)
 462     {
 463         if (exp == null) {
 464             throw new NullPointerException();
 465         }
 466         exponentialSeparator = exp;
 467      }
 468 
 469 
 470     //------------------------------------------------------------
 471     // END     Package Private methods ... to be made public later
 472     //------------------------------------------------------------
 473 
 474     /**
 475      * Standard override.
 476      */

 477     public Object clone() {
 478         try {
 479             return (DecimalFormatSymbols)super.clone();
 480             // other fields are bit-copied
 481         } catch (CloneNotSupportedException e) {
 482             throw new InternalError(e);
 483         }
 484     }
 485 
 486     /**
 487      * Override equals.
 488      */

 489     public boolean equals(Object obj) {
 490         if (obj == null) return false;
 491         if (this == obj) return true;
 492         if (getClass() != obj.getClass()) return false;
 493         DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
 494         return (zeroDigit == other.zeroDigit &&
 495         groupingSeparator == other.groupingSeparator &&
 496         decimalSeparator == other.decimalSeparator &&
 497         percent == other.percent &&
 498         perMill == other.perMill &&
 499         digit == other.digit &&
 500         minusSign == other.minusSign &&
 501         patternSeparator == other.patternSeparator &&
 502         infinity.equals(other.infinity) &&
 503         NaN.equals(other.NaN) &&
 504         currencySymbol.equals(other.currencySymbol) &&
 505         intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
 506         currency == other.currency &&
 507         monetarySeparator == other.monetarySeparator &&
 508         exponentialSeparator.equals(other.exponentialSeparator) &&
 509         locale.equals(other.locale));
 510     }
 511 
 512     /**
 513      * Override hashCode.
 514      */

 515     public int hashCode() {
 516             int result = zeroDigit;
 517             result = result * 37 + groupingSeparator;
 518             result = result * 37 + decimalSeparator;
 519             return result;
 520     }
 521 
 522     /**
 523      * Initializes the symbols from the FormatData resource bundle.
 524      */
 525     private void initialize( Locale locale ) {
 526         this.locale = locale;
 527 
 528         // get resource bundle data - try the cache first
 529         boolean needCacheUpdate = false;
 530         Object[] data = cachedLocaleData.get(locale);
 531         if (data == null) {  /* cache miss */
 532             // When numbering system is thai (Locale's extension contains u-nu-thai),
 533             // we read the data from th_TH_TH.
 534             Locale lookupLocale = locale;
 535             String numberType = locale.getUnicodeLocaleType("nu");
 536             if (numberType != null && numberType.equals("thai")) {
 537                 lookupLocale = new Locale("th", "TH", "TH");

 538             }

 539             data = new Object[3];
 540             ResourceBundle rb = LocaleData.getNumberFormatData(lookupLocale);











 541             data[0] = rb.getStringArray("NumberElements");

 542             needCacheUpdate = true;
 543         }
 544 
 545         String[] numberElements = (String[]) data[0];
 546 
 547         decimalSeparator = numberElements[0].charAt(0);
 548         groupingSeparator = numberElements[1].charAt(0);
 549         patternSeparator = numberElements[2].charAt(0);
 550         percent = numberElements[3].charAt(0);
 551         zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
 552         digit = numberElements[5].charAt(0);
 553         minusSign = numberElements[6].charAt(0);
 554         exponential = numberElements[7].charAt(0);
 555         exponentialSeparator = numberElements[7]; //string representation new since 1.6
 556         perMill = numberElements[8].charAt(0);
 557         infinity  = numberElements[9];
 558         NaN = numberElements[10];
 559 
 560         // Try to obtain the currency used in the locale's country.
 561         // Check for empty country string separately because it's a valid
 562         // country ID for Locale (and used for the C locale), but not a valid
 563         // ISO 3166 country code, and exceptions are expensive.
 564         if (!"".equals(locale.getCountry())) {
 565             try {
 566                 currency = Currency.getInstance(locale);
 567             } catch (IllegalArgumentException e) {
 568                 // use default values below for compatibility
 569             }
 570         }
 571         if (currency != null) {
 572             intlCurrencySymbol = currency.getCurrencyCode();
 573             if (data[1] != null && data[1] == intlCurrencySymbol) {
 574                 currencySymbol = (String) data[2];
 575             } else {
 576                 currencySymbol = currency.getSymbol(locale);
 577                 data[1] = intlCurrencySymbol;
 578                 data[2] = currencySymbol;
 579                 needCacheUpdate = true;
 580             }
 581         } else {
 582             // default values
 583             intlCurrencySymbol = "XXX";
 584             try {


 796      * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
 797      *      two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
 798      * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
 799      *      new <code>locale</code> field.
 800      * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
 801      *      new <code>exponentialSeparator</code> field.
 802      * </ul>
 803      * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
 804      * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
 805      * is always written.
 806      *
 807      * @serial
 808      * @since JDK 1.1.6
 809      */
 810     private int serialVersionOnStream = currentSerialVersion;
 811 
 812     /**
 813      * cache to hold the NumberElements and the Currency
 814      * of a Locale.
 815      */
 816     private static final ConcurrentHashMap<Locale, Object[]> cachedLocaleData = new ConcurrentHashMap<Locale, Object[]>(3);
 817 
 818     /**
 819      * Obtains a DecimalFormatSymbols instance from a DecimalFormatSymbolsProvider
 820      * implementation.
 821      */
 822     private static class DecimalFormatSymbolsGetter
 823         implements LocaleServiceProviderPool.LocalizedObjectGetter<DecimalFormatSymbolsProvider,
 824                                                                    DecimalFormatSymbols> {
 825         private static final DecimalFormatSymbolsGetter INSTANCE =
 826             new DecimalFormatSymbolsGetter();
 827 
 828         public DecimalFormatSymbols getObject(
 829                                 DecimalFormatSymbolsProvider decimalFormatSymbolsProvider,
 830                                 Locale locale,
 831                                 String key,
 832                                 Object... params) {
 833             assert params.length == 0;
 834             return decimalFormatSymbolsProvider.getInstance(locale);
 835         }
 836     }
 837 }
   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


  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 java.util.MissingResourceException;
  48 import java.util.ResourceBundle;
  49 import java.util.concurrent.ConcurrentHashMap;
  50 import java.util.concurrent.ConcurrentMap;
  51 
  52 import sun.util.locale.provider.LocaleProviderAdapter;
  53 import sun.util.locale.provider.LocaleServiceProviderPool;
  54 
  55 /**
  56  * This class represents the set of symbols (such as the decimal separator,
  57  * the grouping separator, and so on) needed by <code>DecimalFormat</code>
  58  * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
  59  * <code>DecimalFormatSymbols</code> from its locale data.  If you need to change any
  60  * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
  61  * your <code>DecimalFormat</code> and modify it.
  62  *
  63  * @see          java.util.Locale
  64  * @see          DecimalFormat
  65  * @author       Mark Davis
  66  * @author       Alan Liu
  67  */
  68 
  69 public class DecimalFormatSymbols implements Cloneable, Serializable {
  70 
  71     /**
  72      * Create a DecimalFormatSymbols object for the default locale.
  73      * This constructor can only construct instances for the locales
  74      * supported by the Java runtime environment, not for those
  75      * supported by installed
  76      * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
  77      * implementations. For full locale coverage, use the
  78      * {@link #getInstance(Locale) getInstance} method.
  79      */
  80     public DecimalFormatSymbols() {
  81         initialize( Locale.getDefault(Locale.Category.FORMAT) );
  82     }
  83 
  84     /**
  85      * Create a DecimalFormatSymbols object for the given locale.
  86      * This constructor can only construct instances for the locales
  87      * supported by the Java runtime environment, not for those
  88      * supported by installed
  89      * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
  90      * implementations. For full locale coverage, use the
  91      * {@link #getInstance(Locale) getInstance} method.
  92      * If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION}
  93      * for the numbering system, the instance is initialized with the specified numbering
  94      * system if the JRE implementation supports it. For example,
  95      * <pre>
  96      * NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai"))
  97      * </pre>
  98      * This may return a {@code NumberFormat} instance with the Thai numbering system,
  99      * instead of the Latin numbering system.
 100      *
 101      * @exception NullPointerException if <code>locale</code> is null
 102      */
 103     public DecimalFormatSymbols( Locale locale ) {
 104         initialize( locale );
 105     }
 106 
 107     /**
 108      * Returns an array of all locales for which the
 109      * <code>getInstance</code> methods of this class can return
 110      * localized instances.
 111      * The returned array represents the union of locales supported by the Java
 112      * runtime and by installed
 113      * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
 114      * implementations.  It must contain at least a <code>Locale</code>
 115      * instance equal to {@link java.util.Locale#US Locale.US}.
 116      *
 117      * @return An array of locales for which localized
 118      *         <code>DecimalFormatSymbols</code> instances are available.
 119      * @since 1.6


 128      * Gets the <code>DecimalFormatSymbols</code> instance for the default
 129      * locale.  This method provides access to <code>DecimalFormatSymbols</code>
 130      * instances for locales supported by the Java runtime itself as well
 131      * as for those supported by installed
 132      * {@link java.text.spi.DecimalFormatSymbolsProvider
 133      * DecimalFormatSymbolsProvider} implementations.
 134      * @return a <code>DecimalFormatSymbols</code> instance.
 135      * @since 1.6
 136      */
 137     public static final DecimalFormatSymbols getInstance() {
 138         return getInstance(Locale.getDefault(Locale.Category.FORMAT));
 139     }
 140 
 141     /**
 142      * Gets the <code>DecimalFormatSymbols</code> instance for the specified
 143      * locale.  This method provides access to <code>DecimalFormatSymbols</code>
 144      * instances for locales supported by the Java runtime itself as well
 145      * as for those supported by installed
 146      * {@link java.text.spi.DecimalFormatSymbolsProvider
 147      * DecimalFormatSymbolsProvider} implementations.
 148      * If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION}
 149      * for the numbering system, the instance is initialized with the specified numbering
 150      * system if the JRE implementation supports it. For example,
 151      * <pre>
 152      * NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai"))
 153      * </pre>
 154      * This may return a {@code NumberFormat} instance with the Thai numbering system,
 155      * instead of the Latin numbering system.
 156      * @param locale the desired locale.
 157      * @return a <code>DecimalFormatSymbols</code> instance.
 158      * @exception NullPointerException if <code>locale</code> is null
 159      * @since 1.6
 160      */
 161     public static final DecimalFormatSymbols getInstance(Locale locale) {
 162         LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
 163         DecimalFormatSymbolsProvider provider = adapter.getLocaleServiceProvider(DecimalFormatSymbolsProvider.class);
 164         return provider.getInstance(locale);







 165     }

 166 



 167     /**
 168      * Gets the character used for zero. Different for Arabic, etc.
 169      */
 170     public char getZeroDigit() {
 171         return zeroDigit;
 172     }
 173 
 174     /**
 175      * Sets the character used for zero. Different for Arabic, etc.
 176      */
 177     public void setZeroDigit(char zeroDigit) {
 178         this.zeroDigit = zeroDigit;
 179     }
 180 
 181     /**
 182      * Gets the character used for thousands separator. Different for French, etc.
 183      */
 184     public char getGroupingSeparator() {
 185         return groupingSeparator;
 186     }


 464    * @exception NullPointerException if <code>exp</code> is null
 465    * @see #getExponentSeparator()
 466    * @since 1.6
 467    */
 468     public void setExponentSeparator(String exp)
 469     {
 470         if (exp == null) {
 471             throw new NullPointerException();
 472         }
 473         exponentialSeparator = exp;
 474      }
 475 
 476 
 477     //------------------------------------------------------------
 478     // END     Package Private methods ... to be made public later
 479     //------------------------------------------------------------
 480 
 481     /**
 482      * Standard override.
 483      */
 484     @Override
 485     public Object clone() {
 486         try {
 487             return (DecimalFormatSymbols)super.clone();
 488             // other fields are bit-copied
 489         } catch (CloneNotSupportedException e) {
 490             throw new InternalError(e);
 491         }
 492     }
 493 
 494     /**
 495      * Override equals.
 496      */
 497     @Override
 498     public boolean equals(Object obj) {
 499         if (obj == null) return false;
 500         if (this == obj) return true;
 501         if (getClass() != obj.getClass()) return false;
 502         DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
 503         return (zeroDigit == other.zeroDigit &&
 504         groupingSeparator == other.groupingSeparator &&
 505         decimalSeparator == other.decimalSeparator &&
 506         percent == other.percent &&
 507         perMill == other.perMill &&
 508         digit == other.digit &&
 509         minusSign == other.minusSign &&
 510         patternSeparator == other.patternSeparator &&
 511         infinity.equals(other.infinity) &&
 512         NaN.equals(other.NaN) &&
 513         currencySymbol.equals(other.currencySymbol) &&
 514         intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
 515         currency == other.currency &&
 516         monetarySeparator == other.monetarySeparator &&
 517         exponentialSeparator.equals(other.exponentialSeparator) &&
 518         locale.equals(other.locale));
 519     }
 520 
 521     /**
 522      * Override hashCode.
 523      */
 524     @Override
 525     public int hashCode() {
 526             int result = zeroDigit;
 527             result = result * 37 + groupingSeparator;
 528             result = result * 37 + decimalSeparator;
 529             return result;
 530     }
 531 
 532     /**
 533      * Initializes the symbols from the FormatData resource bundle.
 534      */
 535     private void initialize( Locale locale ) {
 536         this.locale = locale;
 537 
 538         // get resource bundle data - try the cache first
 539         boolean needCacheUpdate = false;
 540         Object[] data = cachedLocaleData.get(locale);
 541         if (data == null) {  /* cache miss */
 542             LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
 543             // Avoid potential recursions
 544             switch (adapter.getAdapterType()) {
 545             case HOST:
 546             case SPI:
 547                 adapter = LocaleProviderAdapter.getResourceBundleBased();
 548                 break;
 549             }
 550             ResourceBundle rb = adapter.getLocaleData().getNumberFormatData(locale);
 551             data = new Object[3];
 552             String numberType = locale.getUnicodeLocaleType("nu");
 553             StringBuilder numElemKey =
 554                 new StringBuilder(numberType != null ?
 555                                   numberType : rb.getString("DefaultNumberingSystem"));
 556             if (numElemKey.length() != 0) {
 557                 numElemKey.append(".");
 558             }
 559             numElemKey.append("NumberElements");
 560             try {
 561                 data[0] = rb.getStringArray(numElemKey.toString());
 562             } catch (MissingResourceException mre) {
 563                 // numberType must be bogus. Use the last resort numbering system.
 564                 data[0] = rb.getStringArray("NumberElements");
 565             }
 566             needCacheUpdate = true;
 567         }
 568 
 569         String[] numberElements = (String[]) data[0];
 570 
 571         decimalSeparator = numberElements[0].charAt(0);
 572         groupingSeparator = numberElements[1].charAt(0);
 573         patternSeparator = numberElements[2].charAt(0);
 574         percent = numberElements[3].charAt(0);
 575         zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
 576         digit = numberElements[5].charAt(0);
 577         minusSign = numberElements[6].charAt(0);
 578         exponential = numberElements[7].charAt(0);
 579         exponentialSeparator = numberElements[7]; //string representation new since 1.6
 580         perMill = numberElements[8].charAt(0);
 581         infinity  = numberElements[9];
 582         NaN = numberElements[10];
 583 
 584         // Try to obtain the currency used in the locale's country.
 585         // Check for empty country string separately because it's a valid
 586         // country ID for Locale (and used for the C locale), but not a valid
 587         // ISO 3166 country code, and exceptions are expensive.
 588         if (locale.getCountry().length() > 0) {
 589             try {
 590                 currency = Currency.getInstance(locale);
 591             } catch (IllegalArgumentException e) {
 592                 // use default values below for compatibility
 593             }
 594         }
 595         if (currency != null) {
 596             intlCurrencySymbol = currency.getCurrencyCode();
 597             if (data[1] != null && data[1] == intlCurrencySymbol) {
 598                 currencySymbol = (String) data[2];
 599             } else {
 600                 currencySymbol = currency.getSymbol(locale);
 601                 data[1] = intlCurrencySymbol;
 602                 data[2] = currencySymbol;
 603                 needCacheUpdate = true;
 604             }
 605         } else {
 606             // default values
 607             intlCurrencySymbol = "XXX";
 608             try {


 820      * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
 821      *      two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
 822      * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
 823      *      new <code>locale</code> field.
 824      * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
 825      *      new <code>exponentialSeparator</code> field.
 826      * </ul>
 827      * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
 828      * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
 829      * is always written.
 830      *
 831      * @serial
 832      * @since JDK 1.1.6
 833      */
 834     private int serialVersionOnStream = currentSerialVersion;
 835 
 836     /**
 837      * cache to hold the NumberElements and the Currency
 838      * of a Locale.
 839      */
 840     private static final ConcurrentMap<Locale, Object[]> cachedLocaleData = new ConcurrentHashMap<>(3);




















 841 }