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

Print this page
rev 5696 : 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 packaging changes. 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 import sun.util.locale.provider.LocaleProviderAdapter;
  52 import sun.util.locale.provider.LocaleServiceProviderPool;
  53 



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


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



 168         }
 169         return dfsyms;
 170     }
 171 



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


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


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



















 847 }