Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/java/text/DecimalFormatSymbols.java
41152 views
1
/*
2
* Copyright (c) 1996, 2020, 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.InvalidObjectException;
42
import java.io.IOException;
43
import java.io.ObjectInputStream;
44
import java.io.Serializable;
45
import java.text.spi.DecimalFormatSymbolsProvider;
46
import java.util.Currency;
47
import java.util.Locale;
48
import java.util.Objects;
49
import sun.util.locale.provider.CalendarDataUtility;
50
import sun.util.locale.provider.LocaleProviderAdapter;
51
import sun.util.locale.provider.LocaleServiceProviderPool;
52
import sun.util.locale.provider.ResourceBundleBasedAdapter;
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}
57
* to format numbers. {@code DecimalFormat} creates for itself an instance of
58
* {@code DecimalFormatSymbols} from its locale data. If you need to change any
59
* of these symbols, you can get the {@code DecimalFormatSymbols} object from
60
* your {@code DecimalFormat} and modify it.
61
*
62
* <p>If the locale contains "rg" (region override)
63
* <a href="../util/Locale.html#def_locale_extension">Unicode extension</a>,
64
* the symbols are overridden for the designated region.
65
*
66
* @see java.util.Locale
67
* @see DecimalFormat
68
* @author Mark Davis
69
* @author Alan Liu
70
* @since 1.1
71
*/
72
73
public class DecimalFormatSymbols implements Cloneable, Serializable {
74
75
/**
76
* Create a DecimalFormatSymbols object for the default
77
* {@link java.util.Locale.Category#FORMAT FORMAT} locale.
78
* This constructor can only construct instances for the locales
79
* supported by the Java runtime environment, not for those
80
* supported by installed
81
* {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
82
* implementations. For full locale coverage, use the
83
* {@link #getInstance(Locale) getInstance} method.
84
* <p>This is equivalent to calling
85
* {@link #DecimalFormatSymbols(Locale)
86
* DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT))}.
87
* @see java.util.Locale#getDefault(java.util.Locale.Category)
88
* @see java.util.Locale.Category#FORMAT
89
*/
90
public DecimalFormatSymbols() {
91
initialize( Locale.getDefault(Locale.Category.FORMAT) );
92
}
93
94
/**
95
* Create a DecimalFormatSymbols object for the given locale.
96
* This constructor can only construct instances for the locales
97
* supported by the Java runtime environment, not for those
98
* supported by installed
99
* {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
100
* implementations. For full locale coverage, use the
101
* {@link #getInstance(Locale) getInstance} method.
102
* If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION}
103
* for the numbering system, the instance is initialized with the specified numbering
104
* system if the JRE implementation supports it. For example,
105
* <pre>
106
* NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai"))
107
* </pre>
108
* This may return a {@code NumberFormat} instance with the Thai numbering system,
109
* instead of the Latin numbering system.
110
*
111
* @param locale the desired locale
112
* @throws NullPointerException if {@code locale} is null
113
*/
114
public DecimalFormatSymbols( Locale locale ) {
115
initialize( locale );
116
}
117
118
/**
119
* Returns an array of all locales for which the
120
* {@code getInstance} methods of this class can return
121
* localized instances.
122
* The returned array represents the union of locales supported by the Java
123
* runtime and by installed
124
* {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
125
* implementations. It must contain at least a {@code Locale}
126
* instance equal to {@link java.util.Locale#US Locale.US}.
127
*
128
* @return an array of locales for which localized
129
* {@code DecimalFormatSymbols} instances are available.
130
* @since 1.6
131
*/
132
public static Locale[] getAvailableLocales() {
133
LocaleServiceProviderPool pool =
134
LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
135
return pool.getAvailableLocales();
136
}
137
138
/**
139
* Gets the {@code DecimalFormatSymbols} instance for the default
140
* locale. This method provides access to {@code DecimalFormatSymbols}
141
* instances for locales supported by the Java runtime itself as well
142
* as for those supported by installed
143
* {@link java.text.spi.DecimalFormatSymbolsProvider
144
* DecimalFormatSymbolsProvider} implementations.
145
* <p>This is equivalent to calling
146
* {@link #getInstance(Locale)
147
* getInstance(Locale.getDefault(Locale.Category.FORMAT))}.
148
* @see java.util.Locale#getDefault(java.util.Locale.Category)
149
* @see java.util.Locale.Category#FORMAT
150
* @return a {@code DecimalFormatSymbols} instance.
151
* @since 1.6
152
*/
153
public static final DecimalFormatSymbols getInstance() {
154
return getInstance(Locale.getDefault(Locale.Category.FORMAT));
155
}
156
157
/**
158
* Gets the {@code DecimalFormatSymbols} instance for the specified
159
* locale. This method provides access to {@code DecimalFormatSymbols}
160
* instances for locales supported by the Java runtime itself as well
161
* as for those supported by installed
162
* {@link java.text.spi.DecimalFormatSymbolsProvider
163
* DecimalFormatSymbolsProvider} implementations.
164
* If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION}
165
* for the numbering system, the instance is initialized with the specified numbering
166
* system if the JRE implementation supports it. For example,
167
* <pre>
168
* NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai"))
169
* </pre>
170
* This may return a {@code NumberFormat} instance with the Thai numbering system,
171
* instead of the Latin numbering system.
172
*
173
* @param locale the desired locale.
174
* @return a {@code DecimalFormatSymbols} instance.
175
* @throws NullPointerException if {@code locale} is null
176
* @since 1.6
177
*/
178
public static final DecimalFormatSymbols getInstance(Locale locale) {
179
LocaleProviderAdapter adapter;
180
adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
181
DecimalFormatSymbolsProvider provider = adapter.getDecimalFormatSymbolsProvider();
182
DecimalFormatSymbols dfsyms = provider.getInstance(locale);
183
if (dfsyms == null) {
184
provider = LocaleProviderAdapter.forJRE().getDecimalFormatSymbolsProvider();
185
dfsyms = provider.getInstance(locale);
186
}
187
return dfsyms;
188
}
189
190
/**
191
* Gets the character used for zero. Different for Arabic, etc.
192
*
193
* @return the character used for zero
194
*/
195
public char getZeroDigit() {
196
return zeroDigit;
197
}
198
199
/**
200
* Sets the character used for zero. Different for Arabic, etc.
201
*
202
* @param zeroDigit the character used for zero
203
*/
204
public void setZeroDigit(char zeroDigit) {
205
hashCode = 0;
206
this.zeroDigit = zeroDigit;
207
}
208
209
/**
210
* Gets the character used for grouping separator. Different for French, etc.
211
*
212
* @return the grouping separator
213
*/
214
public char getGroupingSeparator() {
215
return groupingSeparator;
216
}
217
218
/**
219
* Sets the character used for grouping separator. Different for French, etc.
220
*
221
* @param groupingSeparator the grouping separator
222
*/
223
public void setGroupingSeparator(char groupingSeparator) {
224
hashCode = 0;
225
this.groupingSeparator = groupingSeparator;
226
}
227
228
/**
229
* Gets the character used for decimal sign. Different for French, etc.
230
*
231
* @return the character used for decimal sign
232
*/
233
public char getDecimalSeparator() {
234
return decimalSeparator;
235
}
236
237
/**
238
* Sets the character used for decimal sign. Different for French, etc.
239
*
240
* @param decimalSeparator the character used for decimal sign
241
*/
242
public void setDecimalSeparator(char decimalSeparator) {
243
hashCode = 0;
244
this.decimalSeparator = decimalSeparator;
245
}
246
247
/**
248
* Gets the character used for per mille sign. Different for Arabic, etc.
249
*
250
* @return the character used for per mille sign
251
*/
252
public char getPerMill() {
253
return perMill;
254
}
255
256
/**
257
* Sets the character used for per mille sign. Different for Arabic, etc.
258
*
259
* @param perMill the character used for per mille sign
260
*/
261
public void setPerMill(char perMill) {
262
hashCode = 0;
263
this.perMill = perMill;
264
this.perMillText = Character.toString(perMill);
265
}
266
267
/**
268
* Gets the character used for percent sign. Different for Arabic, etc.
269
*
270
* @return the character used for percent sign
271
*/
272
public char getPercent() {
273
return percent;
274
}
275
276
/**
277
* Sets the character used for percent sign. Different for Arabic, etc.
278
*
279
* @param percent the character used for percent sign
280
*/
281
public void setPercent(char percent) {
282
hashCode = 0;
283
this.percent = percent;
284
this.percentText = Character.toString(percent);
285
}
286
287
/**
288
* Gets the character used for a digit in a pattern.
289
*
290
* @return the character used for a digit in a pattern
291
*/
292
public char getDigit() {
293
return digit;
294
}
295
296
/**
297
* Sets the character used for a digit in a pattern.
298
*
299
* @param digit the character used for a digit in a pattern
300
*/
301
public void setDigit(char digit) {
302
hashCode = 0;
303
this.digit = digit;
304
}
305
306
/**
307
* Gets the character used to separate positive and negative subpatterns
308
* in a pattern.
309
*
310
* @return the pattern separator
311
*/
312
public char getPatternSeparator() {
313
return patternSeparator;
314
}
315
316
/**
317
* Sets the character used to separate positive and negative subpatterns
318
* in a pattern.
319
*
320
* @param patternSeparator the pattern separator
321
*/
322
public void setPatternSeparator(char patternSeparator) {
323
hashCode = 0;
324
this.patternSeparator = patternSeparator;
325
}
326
327
/**
328
* Gets the string used to represent infinity. Almost always left
329
* unchanged.
330
*
331
* @return the string representing infinity
332
*/
333
public String getInfinity() {
334
return infinity;
335
}
336
337
/**
338
* Sets the string used to represent infinity. Almost always left
339
* unchanged.
340
*
341
* @param infinity the string representing infinity
342
*/
343
public void setInfinity(String infinity) {
344
hashCode = 0;
345
this.infinity = infinity;
346
}
347
348
/**
349
* Gets the string used to represent "not a number". Almost always left
350
* unchanged.
351
*
352
* @return the string representing "not a number"
353
*/
354
public String getNaN() {
355
return NaN;
356
}
357
358
/**
359
* Sets the string used to represent "not a number". Almost always left
360
* unchanged.
361
*
362
* @param NaN the string representing "not a number"
363
*/
364
public void setNaN(String NaN) {
365
hashCode = 0;
366
this.NaN = NaN;
367
}
368
369
/**
370
* Gets the character used to represent minus sign. If no explicit
371
* negative format is specified, one is formed by prefixing
372
* minusSign to the positive format.
373
*
374
* @return the character representing minus sign
375
*/
376
public char getMinusSign() {
377
return minusSign;
378
}
379
380
/**
381
* Sets the character used to represent minus sign. If no explicit
382
* negative format is specified, one is formed by prefixing
383
* minusSign to the positive format.
384
*
385
* @param minusSign the character representing minus sign
386
*/
387
public void setMinusSign(char minusSign) {
388
hashCode = 0;
389
this.minusSign = minusSign;
390
this.minusSignText = Character.toString(minusSign);
391
}
392
393
/**
394
* Returns the currency symbol for the currency of these
395
* DecimalFormatSymbols in their locale.
396
*
397
* @return the currency symbol
398
* @since 1.2
399
*/
400
public String getCurrencySymbol()
401
{
402
initializeCurrency(locale);
403
return currencySymbol;
404
}
405
406
/**
407
* Sets the currency symbol for the currency of these
408
* DecimalFormatSymbols in their locale.
409
*
410
* @param currency the currency symbol
411
* @since 1.2
412
*/
413
public void setCurrencySymbol(String currency)
414
{
415
initializeCurrency(locale);
416
hashCode = 0;
417
currencySymbol = currency;
418
}
419
420
/**
421
* Returns the ISO 4217 currency code of the currency of these
422
* DecimalFormatSymbols.
423
*
424
* @return the currency code
425
* @since 1.2
426
*/
427
public String getInternationalCurrencySymbol()
428
{
429
initializeCurrency(locale);
430
return intlCurrencySymbol;
431
}
432
433
/**
434
* Sets the ISO 4217 currency code of the currency of these
435
* DecimalFormatSymbols.
436
* If the currency code is valid (as defined by
437
* {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}),
438
* this also sets the currency attribute to the corresponding Currency
439
* instance and the currency symbol attribute to the currency's symbol
440
* in the DecimalFormatSymbols' locale. If the currency code is not valid,
441
* then the currency attribute is set to null and the currency symbol
442
* attribute is not modified.
443
*
444
* @param currencyCode the currency code
445
* @see #setCurrency
446
* @see #setCurrencySymbol
447
* @since 1.2
448
*/
449
public void setInternationalCurrencySymbol(String currencyCode)
450
{
451
initializeCurrency(locale);
452
hashCode = 0;
453
intlCurrencySymbol = currencyCode;
454
currency = null;
455
if (currencyCode != null) {
456
try {
457
currency = Currency.getInstance(currencyCode);
458
currencySymbol = currency.getSymbol();
459
} catch (IllegalArgumentException e) {
460
}
461
}
462
}
463
464
/**
465
* Gets the currency of these DecimalFormatSymbols. May be null if the
466
* currency symbol attribute was previously set to a value that's not
467
* a valid ISO 4217 currency code.
468
*
469
* @return the currency used, or null
470
* @since 1.4
471
*/
472
public Currency getCurrency() {
473
initializeCurrency(locale);
474
return currency;
475
}
476
477
/**
478
* Sets the currency of these DecimalFormatSymbols.
479
* This also sets the currency symbol attribute to the currency's symbol
480
* in the DecimalFormatSymbols' locale, and the international currency
481
* symbol attribute to the currency's ISO 4217 currency code.
482
*
483
* @param currency the new currency to be used
484
* @throws NullPointerException if {@code currency} is null
485
* @since 1.4
486
* @see #setCurrencySymbol
487
* @see #setInternationalCurrencySymbol
488
*/
489
public void setCurrency(Currency currency) {
490
if (currency == null) {
491
throw new NullPointerException();
492
}
493
initializeCurrency(locale);
494
hashCode = 0;
495
this.currency = currency;
496
intlCurrencySymbol = currency.getCurrencyCode();
497
currencySymbol = currency.getSymbol(locale);
498
}
499
500
501
/**
502
* Returns the monetary decimal separator.
503
*
504
* @return the monetary decimal separator
505
* @since 1.2
506
*/
507
public char getMonetaryDecimalSeparator()
508
{
509
return monetarySeparator;
510
}
511
512
/**
513
* Sets the monetary decimal separator.
514
*
515
* @param sep the monetary decimal separator
516
* @since 1.2
517
*/
518
public void setMonetaryDecimalSeparator(char sep)
519
{
520
hashCode = 0;
521
monetarySeparator = sep;
522
}
523
524
/**
525
* Returns the string used to separate the mantissa from the exponent.
526
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
527
*
528
* @return the exponent separator string
529
* @see #setExponentSeparator(java.lang.String)
530
* @since 1.6
531
*/
532
public String getExponentSeparator()
533
{
534
return exponentialSeparator;
535
}
536
537
/**
538
* Sets the string used to separate the mantissa from the exponent.
539
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
540
*
541
* @param exp the exponent separator string
542
* @throws NullPointerException if {@code exp} is null
543
* @see #getExponentSeparator()
544
* @since 1.6
545
*/
546
public void setExponentSeparator(String exp)
547
{
548
if (exp == null) {
549
throw new NullPointerException();
550
}
551
hashCode = 0;
552
exponentialSeparator = exp;
553
}
554
555
/**
556
* Gets the character used for grouping separator for currencies.
557
* May be different from {@code grouping separator} in some locales,
558
* e.g, German in Austria.
559
*
560
* @return the monetary grouping separator
561
* @since 15
562
*/
563
public char getMonetaryGroupingSeparator() {
564
return monetaryGroupingSeparator;
565
}
566
567
/**
568
* Sets the character used for grouping separator for currencies.
569
* Invocation of this method will not affect the normal
570
* {@code grouping separator}.
571
*
572
* @param monetaryGroupingSeparator the monetary grouping separator
573
* @see #setGroupingSeparator(char)
574
* @since 15
575
*/
576
public void setMonetaryGroupingSeparator(char monetaryGroupingSeparator)
577
{
578
hashCode = 0;
579
this.monetaryGroupingSeparator = monetaryGroupingSeparator;
580
}
581
582
//------------------------------------------------------------
583
// BEGIN Package Private methods ... to be made public later
584
//------------------------------------------------------------
585
586
/**
587
* Returns the character used to separate the mantissa from the exponent.
588
*/
589
char getExponentialSymbol()
590
{
591
return exponential;
592
}
593
594
/**
595
* Sets the character used to separate the mantissa from the exponent.
596
*/
597
void setExponentialSymbol(char exp)
598
{
599
exponential = exp;
600
}
601
602
/**
603
* Gets the string used for per mille sign. Different for Arabic, etc.
604
*
605
* @return the string used for per mille sign
606
* @since 13
607
*/
608
String getPerMillText() {
609
return perMillText;
610
}
611
612
/**
613
* Sets the string used for per mille sign. Different for Arabic, etc.
614
*
615
* Setting the {@code perMillText} affects the return value of
616
* {@link #getPerMill()}, in which the first non-format character of
617
* {@code perMillText} is returned.
618
*
619
* @param perMillText the string used for per mille sign
620
* @throws NullPointerException if {@code perMillText} is null
621
* @throws IllegalArgumentException if {@code perMillText} is an empty string
622
* @see #getPerMill()
623
* @see #getPerMillText()
624
* @since 13
625
*/
626
void setPerMillText(String perMillText) {
627
Objects.requireNonNull(perMillText);
628
if (perMillText.isEmpty()) {
629
throw new IllegalArgumentException("Empty argument string");
630
}
631
632
hashCode = 0;
633
this.perMillText = perMillText;
634
this.perMill = findNonFormatChar(perMillText, '\u2030');
635
}
636
637
/**
638
* Gets the string used for percent sign. Different for Arabic, etc.
639
*
640
* @return the string used for percent sign
641
* @since 13
642
*/
643
String getPercentText() {
644
return percentText;
645
}
646
647
/**
648
* Sets the string used for percent sign. Different for Arabic, etc.
649
*
650
* Setting the {@code percentText} affects the return value of
651
* {@link #getPercent()}, in which the first non-format character of
652
* {@code percentText} is returned.
653
*
654
* @param percentText the string used for percent sign
655
* @throws NullPointerException if {@code percentText} is null
656
* @throws IllegalArgumentException if {@code percentText} is an empty string
657
* @see #getPercent()
658
* @see #getPercentText()
659
* @since 13
660
*/
661
void setPercentText(String percentText) {
662
Objects.requireNonNull(percentText);
663
if (percentText.isEmpty()) {
664
throw new IllegalArgumentException("Empty argument string");
665
}
666
667
hashCode = 0;
668
this.percentText = percentText;
669
this.percent = findNonFormatChar(percentText, '%');
670
}
671
672
/**
673
* Gets the string used to represent minus sign. If no explicit
674
* negative format is specified, one is formed by prefixing
675
* minusSignText to the positive format.
676
*
677
* @return the string representing minus sign
678
* @since 13
679
*/
680
String getMinusSignText() {
681
return minusSignText;
682
}
683
684
/**
685
* Sets the string used to represent minus sign. If no explicit
686
* negative format is specified, one is formed by prefixing
687
* minusSignText to the positive format.
688
*
689
* Setting the {@code minusSignText} affects the return value of
690
* {@link #getMinusSign()}, in which the first non-format character of
691
* {@code minusSignText} is returned.
692
*
693
* @param minusSignText the character representing minus sign
694
* @throws NullPointerException if {@code minusSignText} is null
695
* @throws IllegalArgumentException if {@code minusSignText} is an
696
* empty string
697
* @see #getMinusSign()
698
* @see #getMinusSignText()
699
* @since 13
700
*/
701
void setMinusSignText(String minusSignText) {
702
Objects.requireNonNull(minusSignText);
703
if (minusSignText.isEmpty()) {
704
throw new IllegalArgumentException("Empty argument string");
705
}
706
707
hashCode = 0;
708
this.minusSignText = minusSignText;
709
this.minusSign = findNonFormatChar(minusSignText, '-');
710
}
711
712
//------------------------------------------------------------
713
// END Package Private methods ... to be made public later
714
//------------------------------------------------------------
715
716
/**
717
* Standard override.
718
*/
719
@Override
720
public Object clone() {
721
try {
722
return (DecimalFormatSymbols)super.clone();
723
// other fields are bit-copied
724
} catch (CloneNotSupportedException e) {
725
throw new InternalError(e);
726
}
727
}
728
729
/**
730
* Override equals.
731
*/
732
@Override
733
public boolean equals(Object obj) {
734
if (obj == null) return false;
735
if (this == obj) return true;
736
if (getClass() != obj.getClass()) return false;
737
DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
738
return (zeroDigit == other.zeroDigit &&
739
groupingSeparator == other.groupingSeparator &&
740
decimalSeparator == other.decimalSeparator &&
741
percent == other.percent &&
742
percentText.equals(other.percentText) &&
743
perMill == other.perMill &&
744
perMillText.equals(other.perMillText) &&
745
digit == other.digit &&
746
minusSign == other.minusSign &&
747
minusSignText.equals(other.minusSignText) &&
748
patternSeparator == other.patternSeparator &&
749
infinity.equals(other.infinity) &&
750
NaN.equals(other.NaN) &&
751
getCurrencySymbol().equals(other.getCurrencySymbol()) && // possible currency init occurs here
752
intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
753
currency == other.currency &&
754
monetarySeparator == other.monetarySeparator &&
755
monetaryGroupingSeparator == other.monetaryGroupingSeparator &&
756
exponentialSeparator.equals(other.exponentialSeparator) &&
757
locale.equals(other.locale));
758
}
759
760
/**
761
* Override hashCode.
762
*/
763
@Override
764
public int hashCode() {
765
if (hashCode == 0) {
766
hashCode = Objects.hash(
767
zeroDigit,
768
groupingSeparator,
769
decimalSeparator,
770
percent,
771
percentText,
772
perMill,
773
perMillText,
774
digit,
775
minusSign,
776
minusSignText,
777
patternSeparator,
778
infinity,
779
NaN,
780
getCurrencySymbol(), // possible currency init occurs here
781
intlCurrencySymbol,
782
currency,
783
monetarySeparator,
784
monetaryGroupingSeparator,
785
exponentialSeparator,
786
locale);
787
}
788
return hashCode;
789
}
790
791
/**
792
* Initializes the symbols from the FormatData resource bundle.
793
*/
794
private void initialize( Locale locale ) {
795
this.locale = locale;
796
797
// check for region override
798
Locale override = locale.getUnicodeLocaleType("nu") == null ?
799
CalendarDataUtility.findRegionOverride(locale) :
800
locale;
801
802
// get resource bundle data
803
LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, override);
804
// Avoid potential recursions
805
if (!(adapter instanceof ResourceBundleBasedAdapter)) {
806
adapter = LocaleProviderAdapter.getResourceBundleBased();
807
}
808
Object[] data = adapter.getLocaleResources(override).getDecimalFormatSymbolsData();
809
String[] numberElements = (String[]) data[0];
810
811
decimalSeparator = numberElements[0].charAt(0);
812
groupingSeparator = numberElements[1].charAt(0);
813
patternSeparator = numberElements[2].charAt(0);
814
percentText = numberElements[3];
815
percent = findNonFormatChar(percentText, '%');
816
zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
817
digit = numberElements[5].charAt(0);
818
minusSignText = numberElements[6];
819
minusSign = findNonFormatChar(minusSignText, '-');
820
exponential = numberElements[7].charAt(0);
821
exponentialSeparator = numberElements[7]; //string representation new since 1.6
822
perMillText = numberElements[8];
823
perMill = findNonFormatChar(perMillText, '\u2030');
824
infinity = numberElements[9];
825
NaN = numberElements[10];
826
827
// monetary decimal/grouping separators may be missing in resource bundles
828
monetarySeparator = numberElements.length < 12 || numberElements[11].isEmpty() ?
829
decimalSeparator : numberElements[11].charAt(0);
830
monetaryGroupingSeparator = numberElements.length < 13 || numberElements[12].isEmpty() ?
831
groupingSeparator : numberElements[12].charAt(0);
832
833
// maybe filled with previously cached values, or null.
834
intlCurrencySymbol = (String) data[1];
835
currencySymbol = (String) data[2];
836
}
837
838
/**
839
* Obtains non-format single character from String
840
*/
841
private char findNonFormatChar(String src, char defChar) {
842
return (char)src.chars()
843
.filter(c -> Character.getType(c) != Character.FORMAT)
844
.findFirst()
845
.orElse(defChar);
846
}
847
848
/**
849
* Lazy initialization for currency related fields
850
*/
851
private void initializeCurrency(Locale locale) {
852
if (currencyInitialized) {
853
return;
854
}
855
856
// Try to obtain the currency used in the locale's country.
857
// Check for empty country string separately because it's a valid
858
// country ID for Locale (and used for the C locale), but not a valid
859
// ISO 3166 country code, and exceptions are expensive.
860
if (!locale.getCountry().isEmpty()) {
861
try {
862
currency = Currency.getInstance(locale);
863
} catch (IllegalArgumentException e) {
864
// use default values below for compatibility
865
}
866
}
867
868
if (currency != null) {
869
// get resource bundle data
870
LocaleProviderAdapter adapter =
871
LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
872
// Avoid potential recursions
873
if (!(adapter instanceof ResourceBundleBasedAdapter)) {
874
adapter = LocaleProviderAdapter.getResourceBundleBased();
875
}
876
Object[] data = adapter.getLocaleResources(locale).getDecimalFormatSymbolsData();
877
intlCurrencySymbol = currency.getCurrencyCode();
878
if (data[1] != null && data[1] == intlCurrencySymbol) {
879
currencySymbol = (String) data[2];
880
} else {
881
currencySymbol = currency.getSymbol(locale);
882
data[1] = intlCurrencySymbol;
883
data[2] = currencySymbol;
884
}
885
} else {
886
// default values
887
intlCurrencySymbol = "XXX";
888
try {
889
currency = Currency.getInstance(intlCurrencySymbol);
890
} catch (IllegalArgumentException e) {
891
}
892
currencySymbol = "\u00A4";
893
}
894
895
currencyInitialized = true;
896
}
897
898
/**
899
* Reads the default serializable fields, provides default values for objects
900
* in older serial versions, and initializes non-serializable fields.
901
* If {@code serialVersionOnStream}
902
* is less than 1, initializes {@code monetarySeparator} to be
903
* the same as {@code decimalSeparator} and {@code exponential}
904
* to be 'E'.
905
* If {@code serialVersionOnStream} is less than 2,
906
* initializes {@code locale} to the root locale, and initializes
907
* If {@code serialVersionOnStream} is less than 3, it initializes
908
* {@code exponentialSeparator} using {@code exponential}.
909
* If {@code serialVersionOnStream} is less than 4, it initializes
910
* {@code perMillText}, {@code percentText}, and
911
* {@code minusSignText} using {@code perMill}, {@code percent}, and
912
* {@code minusSign} respectively.
913
* If {@code serialVersionOnStream} is less than 5, it initializes
914
* {@code monetaryGroupingSeparator} using {@code groupingSeparator}.
915
* Sets {@code serialVersionOnStream} back to the maximum allowed value so that
916
* default serialization will work properly if this object is streamed out again.
917
* Initializes the currency from the intlCurrencySymbol field.
918
*
919
* @throws InvalidObjectException if {@code char} and {@code String}
920
* representations of either percent, per mille, and/or minus sign disagree.
921
* @since 1.1.6
922
*/
923
@java.io.Serial
924
private void readObject(ObjectInputStream stream)
925
throws IOException, ClassNotFoundException {
926
stream.defaultReadObject();
927
if (serialVersionOnStream < 1) {
928
// Didn't have monetarySeparator or exponential field;
929
// use defaults.
930
monetarySeparator = decimalSeparator;
931
exponential = 'E';
932
}
933
if (serialVersionOnStream < 2) {
934
// didn't have locale; use root locale
935
locale = Locale.ROOT;
936
}
937
if (serialVersionOnStream < 3) {
938
// didn't have exponentialSeparator. Create one using exponential
939
exponentialSeparator = Character.toString(exponential);
940
}
941
if (serialVersionOnStream < 4) {
942
// didn't have perMillText, percentText, and minusSignText.
943
// Create one using corresponding char variations.
944
perMillText = Character.toString(perMill);
945
percentText = Character.toString(percent);
946
minusSignText = Character.toString(minusSign);
947
} else {
948
// Check whether char and text fields agree
949
if (findNonFormatChar(perMillText, '\uFFFF') != perMill ||
950
findNonFormatChar(percentText, '\uFFFF') != percent ||
951
findNonFormatChar(minusSignText, '\uFFFF') != minusSign) {
952
throw new InvalidObjectException(
953
"'char' and 'String' representations of either percent, " +
954
"per mille, and/or minus sign disagree.");
955
}
956
}
957
if (serialVersionOnStream < 5) {
958
// didn't have monetaryGroupingSeparator. Create one using groupingSeparator
959
monetaryGroupingSeparator = groupingSeparator;
960
}
961
962
serialVersionOnStream = currentSerialVersion;
963
964
if (intlCurrencySymbol != null) {
965
try {
966
currency = Currency.getInstance(intlCurrencySymbol);
967
} catch (IllegalArgumentException e) {
968
}
969
currencyInitialized = true;
970
}
971
}
972
973
/**
974
* Character used for zero.
975
*
976
* @serial
977
* @see #getZeroDigit
978
*/
979
private char zeroDigit;
980
981
/**
982
* Character used for grouping separator.
983
*
984
* @serial
985
* @see #getGroupingSeparator
986
*/
987
private char groupingSeparator;
988
989
/**
990
* Character used for decimal sign.
991
*
992
* @serial
993
* @see #getDecimalSeparator
994
*/
995
private char decimalSeparator;
996
997
/**
998
* Character used for per mille sign.
999
*
1000
* @serial
1001
* @see #getPerMill
1002
*/
1003
private char perMill;
1004
1005
/**
1006
* Character used for percent sign.
1007
* @serial
1008
* @see #getPercent
1009
*/
1010
private char percent;
1011
1012
/**
1013
* Character used for a digit in a pattern.
1014
*
1015
* @serial
1016
* @see #getDigit
1017
*/
1018
private char digit;
1019
1020
/**
1021
* Character used to separate positive and negative subpatterns
1022
* in a pattern.
1023
*
1024
* @serial
1025
* @see #getPatternSeparator
1026
*/
1027
private char patternSeparator;
1028
1029
/**
1030
* String used to represent infinity.
1031
* @serial
1032
* @see #getInfinity
1033
*/
1034
private String infinity;
1035
1036
/**
1037
* String used to represent "not a number".
1038
* @serial
1039
* @see #getNaN
1040
*/
1041
private String NaN;
1042
1043
/**
1044
* Character used to represent minus sign.
1045
* @serial
1046
* @see #getMinusSign
1047
*/
1048
private char minusSign;
1049
1050
/**
1051
* String denoting the local currency, e.g. "$".
1052
* @serial
1053
* @see #getCurrencySymbol
1054
*/
1055
private String currencySymbol;
1056
1057
/**
1058
* ISO 4217 currency code denoting the local currency, e.g. "USD".
1059
* @serial
1060
* @see #getInternationalCurrencySymbol
1061
*/
1062
private String intlCurrencySymbol;
1063
1064
/**
1065
* The decimal separator used when formatting currency values.
1066
* @serial
1067
* @since 1.1.6
1068
* @see #getMonetaryDecimalSeparator
1069
*/
1070
private char monetarySeparator; // Field new in JDK 1.1.6
1071
1072
/**
1073
* The character used to distinguish the exponent in a number formatted
1074
* in exponential notation, e.g. 'E' for a number such as "1.23E45".
1075
* <p>
1076
* Note that the public API provides no way to set this field,
1077
* even though it is supported by the implementation and the stream format.
1078
* The intent is that this will be added to the API in the future.
1079
*
1080
* @serial
1081
* @since 1.1.6
1082
*/
1083
private char exponential; // Field new in JDK 1.1.6
1084
1085
/**
1086
* The string used to separate the mantissa from the exponent.
1087
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
1088
* <p>
1089
* If both {@code exponential} and {@code exponentialSeparator}
1090
* exist, this {@code exponentialSeparator} has the precedence.
1091
*
1092
* @serial
1093
* @since 1.6
1094
*/
1095
private String exponentialSeparator; // Field new in JDK 1.6
1096
1097
/**
1098
* The locale of these currency format symbols.
1099
*
1100
* @serial
1101
* @since 1.4
1102
*/
1103
private Locale locale;
1104
1105
/**
1106
* String representation of per mille sign, which may include
1107
* formatting characters, such as BiDi control characters.
1108
* The first non-format character of this string is the same as
1109
* {@code perMill}.
1110
*
1111
* @serial
1112
* @since 13
1113
*/
1114
private String perMillText;
1115
1116
/**
1117
* String representation of percent sign, which may include
1118
* formatting characters, such as BiDi control characters.
1119
* The first non-format character of this string is the same as
1120
* {@code percent}.
1121
*
1122
* @serial
1123
* @since 13
1124
*/
1125
private String percentText;
1126
1127
/**
1128
* String representation of minus sign, which may include
1129
* formatting characters, such as BiDi control characters.
1130
* The first non-format character of this string is the same as
1131
* {@code minusSign}.
1132
*
1133
* @serial
1134
* @since 13
1135
*/
1136
private String minusSignText;
1137
1138
/**
1139
* The grouping separator used when formatting currency values.
1140
*
1141
* @serial
1142
* @since 15
1143
*/
1144
private char monetaryGroupingSeparator;
1145
1146
// currency; only the ISO code is serialized.
1147
private transient Currency currency;
1148
private transient volatile boolean currencyInitialized;
1149
1150
/**
1151
* Cached hash code.
1152
*/
1153
private transient volatile int hashCode;
1154
1155
// Proclaim JDK 1.1 FCS compatibility
1156
@java.io.Serial
1157
static final long serialVersionUID = 5772796243397350300L;
1158
1159
// The internal serial version which says which version was written
1160
// - 0 (default) for version up to JDK 1.1.5
1161
// - 1 for version from JDK 1.1.6, which includes two new fields:
1162
// monetarySeparator and exponential.
1163
// - 2 for version from J2SE 1.4, which includes locale field.
1164
// - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
1165
// - 4 for version from Java SE 13, which includes perMillText, percentText,
1166
// and minusSignText field.
1167
// - 5 for version from Java SE 15, which includes monetaryGroupingSeparator.
1168
private static final int currentSerialVersion = 5;
1169
1170
/**
1171
* Describes the version of {@code DecimalFormatSymbols} present on the stream.
1172
* Possible values are:
1173
* <ul>
1174
* <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
1175
*
1176
* <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
1177
* two new fields: {@code monetarySeparator} and {@code exponential}.
1178
* <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
1179
* new {@code locale} field.
1180
* <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
1181
* new {@code exponentialSeparator} field.
1182
* <li><b>4</b>: Versions written by Java SE 13 or later, which include
1183
* new {@code perMillText}, {@code percentText}, and
1184
* {@code minusSignText} field.
1185
* <li><b>5</b>: Versions written by Java SE 15 or later, which include
1186
* new {@code monetaryGroupingSeparator} field.
1187
* * </ul>
1188
* When streaming out a {@code DecimalFormatSymbols}, the most recent format
1189
* (corresponding to the highest allowable {@code serialVersionOnStream})
1190
* is always written.
1191
*
1192
* @serial
1193
* @since 1.1.6
1194
*/
1195
private int serialVersionOnStream = currentSerialVersion;
1196
}
1197
1198