1. /*
  2. * @(#)DecimalFormatSymbols.java 1.30 00/01/19
  3. *
  4. * Copyright 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. /*
  11. * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  12. * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  13. *
  14. * The original version of this source code and documentation is copyrighted
  15. * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  16. * materials are provided under terms of a License Agreement between Taligent
  17. * and Sun. This technology is protected by multiple US and International
  18. * patents. This notice and attribution to Taligent may not be removed.
  19. * Taligent is a registered trademark of Taligent, Inc.
  20. *
  21. */
  22. package java.text;
  23. import java.io.IOException;
  24. import java.io.ObjectInputStream;
  25. import java.io.Serializable;
  26. import java.util.ResourceBundle;
  27. import java.util.Locale;
  28. import java.util.Hashtable;
  29. /**
  30. * This class represents the set of symbols (such as the decimal separator,
  31. * the grouping separator, and so on) needed by <code>DecimalFormat</code>
  32. * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
  33. * <code>DecimalFormatSymbols</code> from its locale data. If you need to change any
  34. * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
  35. * your <code>DecimalFormat</code> and modify it.
  36. *
  37. * @see java.util.Locale
  38. * @see DecimalFormat
  39. * @version 1.30, 01/19/00
  40. * @author Mark Davis
  41. * @author Alan Liu
  42. */
  43. final public class DecimalFormatSymbols implements Cloneable, Serializable {
  44. /**
  45. * Create a DecimalFormatSymbols object for the default locale.
  46. */
  47. public DecimalFormatSymbols() {
  48. initialize( Locale.getDefault() );
  49. }
  50. /**
  51. * Create a DecimalFormatSymbols object for the given locale.
  52. */
  53. public DecimalFormatSymbols( Locale locale ) {
  54. initialize( locale );
  55. }
  56. /**
  57. * Gets the character used for zero. Different for Arabic, etc.
  58. */
  59. public char getZeroDigit() {
  60. return zeroDigit;
  61. }
  62. /**
  63. * Set the character used for zero. Different for Arabic, etc.
  64. */
  65. public void setZeroDigit(char zeroDigit) {
  66. this.zeroDigit = zeroDigit;
  67. }
  68. /**
  69. * Gets the character used for thousands separator. Different for French, etc.
  70. */
  71. public char getGroupingSeparator() {
  72. return groupingSeparator;
  73. }
  74. /**
  75. * Set the character used for thousands separator. Different for French, etc.
  76. */
  77. public void setGroupingSeparator(char groupingSeparator) {
  78. this.groupingSeparator = groupingSeparator;
  79. }
  80. /**
  81. * Gets the character used for decimal sign. Different for French, etc.
  82. */
  83. public char getDecimalSeparator() {
  84. return decimalSeparator;
  85. }
  86. /**
  87. * Set the character used for decimal sign. Different for French, etc.
  88. */
  89. public void setDecimalSeparator(char decimalSeparator) {
  90. this.decimalSeparator = decimalSeparator;
  91. }
  92. /**
  93. * Gets the character used for mille percent sign. Different for Arabic, etc.
  94. */
  95. public char getPerMill() {
  96. return perMill;
  97. }
  98. /**
  99. * Set the character used for mille percent sign. Different for Arabic, etc.
  100. */
  101. public void setPerMill(char perMill) {
  102. this.perMill = perMill;
  103. }
  104. /**
  105. * Gets the character used for percent sign. Different for Arabic, etc.
  106. */
  107. public char getPercent() {
  108. return percent;
  109. }
  110. /**
  111. * Set the character used for percent sign. Different for Arabic, etc.
  112. */
  113. public void setPercent(char percent) {
  114. this.percent = percent;
  115. }
  116. /**
  117. * Gets the character used for a digit in a pattern.
  118. */
  119. public char getDigit() {
  120. return digit;
  121. }
  122. /**
  123. * Set the character used for a digit in a pattern.
  124. */
  125. public void setDigit(char digit) {
  126. this.digit = digit;
  127. }
  128. /**
  129. * Gets the character used to separate positive and negative subpatterns
  130. * in a pattern.
  131. */
  132. public char getPatternSeparator() {
  133. return patternSeparator;
  134. }
  135. /**
  136. * Set the character used to separate positive and negative subpatterns
  137. * in a pattern.
  138. */
  139. public void setPatternSeparator(char patternSeparator) {
  140. this.patternSeparator = patternSeparator;
  141. }
  142. /**
  143. * Gets the character used to represent infinity. Almost always left
  144. * unchanged.
  145. */
  146. public String getInfinity() {
  147. return infinity;
  148. }
  149. /**
  150. * Set the character used to represent infinity. Almost always left
  151. * unchanged.
  152. */
  153. public void setInfinity(String infinity) {
  154. this.infinity = infinity;
  155. }
  156. /**
  157. * Gets the character used to represent NaN. Almost always left
  158. * unchanged.
  159. */
  160. public String getNaN() {
  161. return NaN;
  162. }
  163. /**
  164. * Set the character used to represent NaN. Almost always left
  165. * unchanged.
  166. */
  167. public void setNaN(String NaN) {
  168. this.NaN = NaN;
  169. }
  170. /**
  171. * Gets the character used to represent minus sign. If no explicit
  172. * negative format is specified, one is formed by prefixing
  173. * minusSign to the positive format.
  174. */
  175. public char getMinusSign() {
  176. return minusSign;
  177. }
  178. /**
  179. * Set the character used to represent minus sign. If no explicit
  180. * negative format is specified, one is formed by prefixing
  181. * minusSign to the positive format.
  182. */
  183. public void setMinusSign(char minusSign) {
  184. this.minusSign = minusSign;
  185. }
  186. /**
  187. * Return the string denoting the local currency.
  188. */
  189. public String getCurrencySymbol()
  190. {
  191. return currencySymbol;
  192. }
  193. /**
  194. * Set the string denoting the local currency.
  195. */
  196. public void setCurrencySymbol(String currency)
  197. {
  198. currencySymbol = currency;
  199. }
  200. /**
  201. * Return the international string denoting the local currency.
  202. */
  203. public String getInternationalCurrencySymbol()
  204. {
  205. return intlCurrencySymbol;
  206. }
  207. /**
  208. * Set the international string denoting the local currency.
  209. */
  210. public void setInternationalCurrencySymbol(String currency)
  211. {
  212. intlCurrencySymbol = currency;
  213. }
  214. /**
  215. * Return the monetary decimal separator.
  216. */
  217. public char getMonetaryDecimalSeparator()
  218. {
  219. return monetarySeparator;
  220. }
  221. /**
  222. * Set the monetary decimal separator.
  223. */
  224. public void setMonetaryDecimalSeparator(char sep)
  225. {
  226. monetarySeparator = sep;
  227. }
  228. //------------------------------------------------------------
  229. // BEGIN Package Private methods ... to be made public later
  230. //------------------------------------------------------------
  231. /**
  232. * Return the character used to separate the mantissa from the exponent.
  233. */
  234. char getExponentialSymbol()
  235. {
  236. return exponential;
  237. }
  238. /**
  239. * Set the character used to separate the mantissa from the exponent.
  240. */
  241. void setExponentialSymbol(char exp)
  242. {
  243. exponential = exp;
  244. }
  245. //------------------------------------------------------------
  246. // END Package Private methods ... to be made public later
  247. //------------------------------------------------------------
  248. /**
  249. * Standard override.
  250. */
  251. public Object clone() {
  252. try {
  253. return (DecimalFormatSymbols)super.clone();
  254. // other fields are bit-copied
  255. } catch (CloneNotSupportedException e) {
  256. throw new InternalError();
  257. }
  258. }
  259. /**
  260. * Override equals.
  261. */
  262. public boolean equals(Object obj) {
  263. if (obj == null) return false;
  264. if (this == obj) return true;
  265. if (getClass() != obj.getClass()) return false;
  266. DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
  267. return (zeroDigit == other.zeroDigit &&
  268. groupingSeparator == other.groupingSeparator &&
  269. decimalSeparator == other.decimalSeparator &&
  270. percent == other.percent &&
  271. perMill == other.perMill &&
  272. digit == other.digit &&
  273. minusSign == other.minusSign &&
  274. patternSeparator == other.patternSeparator &&
  275. infinity.equals(other.infinity) &&
  276. NaN.equals(other.NaN) &&
  277. currencySymbol.equals(other.currencySymbol) &&
  278. intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
  279. monetarySeparator == other.monetarySeparator);
  280. }
  281. /**
  282. * Override hashCode.
  283. */
  284. public int hashCode() {
  285. int result = zeroDigit;
  286. result = result * 37 + groupingSeparator;
  287. result = result * 37 + decimalSeparator;
  288. return result;
  289. }
  290. /**
  291. * Initializes the symbols from the LocaleElements resource bundle.
  292. * Note: The organization of LocaleElements badly needs to be
  293. * cleaned up.
  294. */
  295. private void initialize( Locale locale ) {
  296. /* try the cache first */
  297. String[][] data = (String[][]) cachedLocaleData.get(locale);
  298. String[] numberElements;
  299. String[] currencyElements;
  300. if (data == null) { /* cache miss */
  301. data = new String[2][];
  302. ResourceBundle rb = ResourceBundle.getBundle
  303. ("java.text.resources.LocaleElements", locale);
  304. data[0] = rb.getStringArray("NumberElements");
  305. data[1] = rb.getStringArray("CurrencyElements");
  306. /* update cache */
  307. cachedLocaleData.put(locale, data);
  308. }
  309. numberElements = data[0];
  310. currencyElements = data[1];
  311. decimalSeparator = numberElements[0].charAt(0);
  312. groupingSeparator = numberElements[1].charAt(0);
  313. patternSeparator = numberElements[2].charAt(0);
  314. percent = numberElements[3].charAt(0);
  315. zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
  316. digit = numberElements[5].charAt(0);
  317. minusSign = numberElements[6].charAt(0);
  318. exponential = numberElements[7].charAt(0);
  319. perMill = numberElements[8].charAt(0);
  320. infinity = numberElements[9];
  321. NaN = numberElements[10];
  322. currencySymbol = currencyElements[0];
  323. intlCurrencySymbol = currencyElements[1];
  324. // if the resource data specified the empty string as the monetary decimal
  325. // separator, that means we should just use the regular separator as the
  326. // monetary separator
  327. if (currencyElements[2].length() == 0)
  328. monetarySeparator = decimalSeparator;
  329. else
  330. monetarySeparator = currencyElements[2].charAt(0);
  331. }
  332. /**
  333. * Read the default serializable fields, then if <code>serialVersionOnStream</code>
  334. * is less than 1, initialize <code>monetarySeparator</code> to be
  335. * the same as <code>decimalSeparator</code> and <code>exponential</code>
  336. * to be 'E'.
  337. * Finally, set serialVersionOnStream back to the maximum allowed value so that
  338. * default serialization will work properly if this object is streamed out again.
  339. *
  340. * @since JDK 1.1.6
  341. */
  342. private void readObject(ObjectInputStream stream)
  343. throws IOException, ClassNotFoundException
  344. {
  345. stream.defaultReadObject();
  346. if (serialVersionOnStream < 1)
  347. {
  348. // Didn't have monetarySeparator or exponential field;
  349. // use defaults.
  350. monetarySeparator = decimalSeparator;
  351. exponential = 'E';
  352. }
  353. serialVersionOnStream = currentSerialVersion;
  354. }
  355. /**
  356. * Character used for zero.
  357. *
  358. * @serial
  359. * @see #getZeroDigit
  360. */
  361. private char zeroDigit;
  362. /**
  363. * Character used for thousands separator.
  364. *
  365. * @serial
  366. * @see #getGroupingSeparator
  367. */
  368. private char groupingSeparator;
  369. /**
  370. * Character used for decimal sign.
  371. *
  372. * @serial
  373. * @see #getDecimalSeparator
  374. */
  375. private char decimalSeparator;
  376. /**
  377. * Character used for mille percent sign.
  378. *
  379. * @serial
  380. * @see #getPerMill
  381. */
  382. private char perMill;
  383. /**
  384. * Character used for percent sign.
  385. * @serial
  386. * @see #getPercent
  387. */
  388. private char percent;
  389. /**
  390. * Character used for a digit in a pattern.
  391. *
  392. * @serial
  393. * @see #getDigit
  394. */
  395. private char digit;
  396. /**
  397. * Character used to separate positive and negative subpatterns
  398. * in a pattern.
  399. *
  400. * @serial
  401. * @see #getPatternSeparator
  402. */
  403. private char patternSeparator;
  404. /**
  405. * Character used to represent infinity.
  406. * @serial
  407. * @see #getInfinity
  408. */
  409. private String infinity;
  410. /**
  411. * Character used to represent NaN.
  412. * @serial
  413. * @see #getNaN
  414. */
  415. private String NaN;
  416. /**
  417. * Character used to represent minus sign.
  418. * @serial
  419. * @see #getMinusSign
  420. */
  421. private char minusSign;
  422. /**
  423. * String denoting the local currency, e.g. "$".
  424. * @serial
  425. * @see #getCurrencySymbol
  426. */
  427. private String currencySymbol;
  428. /**
  429. * International string denoting the local currency, e.g. "USD".
  430. * @serial
  431. * @see #getInternationalCurrencySymbol
  432. */
  433. private String intlCurrencySymbol;
  434. /**
  435. * The decimal separator used when formatting currency values.
  436. * @serial
  437. * @since JDK 1.1.6
  438. * @see #getMonetaryDecimalSeparator
  439. */
  440. private char monetarySeparator; // Field new in JDK 1.1.6
  441. /**
  442. * The character used to distinguish the exponent in a number formatted
  443. * in exponential notation, e.g. 'E' for a number such as "1.23E45".
  444. * <p>
  445. * Note that the public API provides no way to set this field,
  446. * even though it is supported by the implementation and the stream format.
  447. * The intent is that this will be added to the API in the future.
  448. *
  449. * @serial
  450. * @since JDK 1.1.6
  451. */
  452. private char exponential; // Field new in JDK 1.1.6
  453. // Proclaim JDK 1.1 FCS compatibility
  454. static final long serialVersionUID = 5772796243397350300L;
  455. // The internal serial version which says which version was written
  456. // - 0 (default) for version up to JDK 1.1.5
  457. // - 1 for version from JDK 1.1.6, which includes two new fields:
  458. // monetarySeparator and exponential.
  459. private static final int currentSerialVersion = 1;
  460. /**
  461. * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
  462. * Possible values are:
  463. * <ul>
  464. * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
  465. *
  466. * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which includes
  467. * two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
  468. * </ul>
  469. * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
  470. * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
  471. * is always written.
  472. *
  473. * @serial
  474. * @since JDK 1.1.6
  475. */
  476. private int serialVersionOnStream = currentSerialVersion;
  477. /**
  478. * cache to hold the NumberElements and the CurrencyElements
  479. * of a Locale.
  480. */
  481. private static final Hashtable cachedLocaleData = new Hashtable(3);
  482. }