技术开发 频道

JAVA:3个常用的JDK对象详细解析

  【IT168技术】 本篇主要介绍的是我们在日常开发中经常用到的JDK对象,这里进行了一些分类性总结和差异比较。由于这里涉及的很多工具类都是大家耳熟能详的,因此不会长篇大论的介绍每一个概念和细节,我们还是继续秉承该系列的风格,通过更多实用的可执行的示例代码和关键性注释来阐述他们的功能和技术细节,让我们现在就开始吧。

  大数值对象(BigDecimal)

  和普通的原始类型相比,该类主要提供以下几点优势:

  ①可以表示任意大十进制数值;

  ② 提供了基本的数学函数,同时也支持各种数学运算符;

  ③ 提供了与字符串(String)和原始数值类型之间的各种转换;

  ④ 与double和Double相比,在进行浮点运算时不丢失精度;

  ⑤ 提供可靠的四舍五入表示。

  那么的劣势又是什么呢?性能!因此如果我们的系统需要进行大量的科学计算,那么BigDecimal将不是一个很好的选择,特别是对那些高密度计算的程序,在这种情况下我们的首选还是原始数据类型。因此BigDecimal更适用于基于商业规则的运算程序,如保单和利息等。

  下面将给出几个比较典型的应用示例:

  ① BigDecimal与String和任意数值类型的转换:

 1     public static void main(String args[]) {
2 BigDecimal bd1 = new BigDecimal("123456789.0123456890");
3 BigDecimal bd2 = BigDecimal.valueOf(123L);
4 bd1 = bd1.add(bd2);
5 System.out.println(bd2.toPlainString());
6 BigDecimal bd3 = new BigDecimal(bd2.toPlainString());
7 if (bd3.equals(bd2))
8 System.out.println("bd2 is equal to bd3");
9 if (bd2.intValue() == 123)
10 System.out.println("bd2 is equal to 123.");
11 }
12 /* 输出结果如下:
13 123
14 bd2 is equal to bd3
15 bd2 is equal to 123.
16 */

  由上例的输出结果可见,BigDecimal中提供了各种类型之间的可传递性转换,既上例中的bd2对象,源于123L,然后再将该对象转换会原始类型时,得到的值和之前初始化该对象的值仍然是相等的。上例中还用将bd2转换为字符串,并用该结果构造了另外一个BigDecimal对象,在比较这个两个对象的值时,发现他们是相等的。这种可传递性的类型之间的转换,Effective Java的作者是比较推崇的。

  ② 基本的数学运算和数学函数应用:

1     public static void main(String args[]) {
2 BigDecimal bd1 = new BigDecimal("123456789.0123456890");
3         BigDecimal bd2 = BigDecimal.valueOf(123L);
4         bd1 = bd1.add(bd2);
5         System.out.printf("bd1 = %s after add.\n",bd1.toPlainString());
6         bd1 = bd1.multiply(bd2);
7         System.out.printf("bd1 = %s after multiply.\n",bd1.toPlainString());
8         bd1 = bd1.subtract(bd2);
9         System.out.printf("bd1 = %s after subtract.\n",bd1.toPlainString());
10         bd1 = bd1.divide(bd2, BigDecimal.ROUND_UP);
11         System.out.printf("bd1 = %s after divide.\n",bd1.toPlainString());
12         bd1 = bd1.negate();
13         System.out.printf("bd1 = %s after negate.\n",bd1.toPlainString());
14         System.out.println("The power of db2(123) is " + bd2.pow(2).toPlainString());
15     }
16     /*    输出结果如下:
17         bd1 = 123456912.0123456890 after add.
18         bd1 = 15185200177.5185197470 after multiply.
19         bd1 = 15185200054.5185197470 after subtract.
20         bd1 = 123456911.0123456890 after divide.
21         bd1 = -123456911.0123456890 after negate.
22         The power of db2(123) is 15129
23     */

   从结果中可以看出没有丢失精度。

  ③ 基于刻度的进位:

 1     public static void main(String args[]) {
2 int decimalPlaces = 2;
3 BigDecimal bd = new BigDecimal("123456789.0123456890");
4 //始终向下舍位
5 BigDecimal bd1 = bd.setScale(decimalPlaces, BigDecimal.ROUND_DOWN);
6 System.out.println(bd1.toString());
7 //始终向上进位
8 BigDecimal bd2 = bd.setScale(decimalPlaces, BigDecimal.ROUND_UP);
9 System.out.println(bd2.toString());
10 BigDecimal bd3 = new BigDecimal(3.14159);
11 //四舍五入
12 bd3 = bd3.setScale(3, BigDecimal.ROUND_HALF_UP);
13 System.out.println(bd3.toString());
14 }
15 /* 输出结果如下:
16 123456789.01
17 123456789.02
18 3.142
19 */

  大整型对象(BigInteger)

  BigInteger和BigDecimal相比,大部分的功能是相同的,主要的差异为BigInteger仅仅表示大整数的封装,而不能表示浮点数,与此同时,BigInteger还提供了大量的位操作运算,这个和C++中的BitSet非常类似。如果我们的在应用中只是需要大整数,那么应该首先该类,而不是BigDecimal,如果我们的应用逻辑中有多于64种状态(long表示64bits)的情况,可以考虑用BigInteger的位操作功能。

  ①基本的数学运算和数学函数应用:

 1     public static void main(String args[]) {
2 BigInteger bi1 = new BigInteger("1234567890123456890");
3 BigInteger bi2 = BigInteger.valueOf(123L);
4 System.out.printf("bi1 = %s after added\n",bi1.add(bi2));
5 System.out.printf("bi1 = %s after multiply\n",bi1.multiply(bi2));
6 System.out.printf("bi1 = %s after subtract\n",bi1.subtract(bi2));
7 System.out.printf("bi1 = %s after divide\n",bi1.divide(bi2));
8 System.out.printf("bi1 = %s after negate\n",bi1.negate());
9 int exponent = 2;
10 System.out.printf("bi1 = %s after pow\n",bi1.pow(exponent));
11 }
12 /* 输出结果如下:
13 bi1 = 1234567890123457013 after added
14 bi1 = 151851850485185197470 after multiply
15 bi1 = 1234567890123456767 after subtract
16 bi1 = 10037137318076885 after divide
17 bi1 = -1234567890123456890 after negate
18 bi1 = 1524157875323883924401765803688472100 after pow
19 */

  ②将BigInteger的值转换为各种进制的字符串表示:

 1     public static void main(String args[]) {
2 BigInteger number = new BigInteger("2008");
3 System.out.println("Number = " + number);
4 System.out.println("Binary = " + number.toString(2));
5 System.out.println("Octal = " + number.toString(8));
6 System.out.println("Hexadecimal = " + number.toString(16));
7 number = new BigInteger("FF", 16);
8 System.out.println("Number = " + number);
9 System.out.println("Number = " + number.toString(16));
10 }
11 /* 输出结果如下:
12 Number = 2008
13 Binary = 11111011000
14 Octal = 3730
15 Hexadecimal = 7d8
16 Number = 255
17 Number = ff
18 */

  ③ 从字符串构造各种进制的BigInteger对象:

 1     public static void main(String args[]) {
2 BigInteger bi = new BigInteger("120ff0", 16);
3 Integer ii = Integer.valueOf("120ff0", 16);
4 if (bi.intValue() == ii.intValue())
5 System.out.println("bi.intValue == ii.intValue");
6 System.out.println("int i = " + bi.intValue());
7
8 BigInteger bi2 = new BigInteger("100100100111111110000", 2);
9 System.out.println(bi2.intValue());
10 }
11 /* 输出结果如下:
12 bi.intValue == ii.intValue
13 int i = 1183728
14 1200112
15 */

  ④ 位操作:

1     public static void main(String args[]) {
2         byte[] bytes = new byte[] { 0x1, 0x00, 0x00 };
3         BigInteger bi = new BigInteger(bytes);
4         //相当于 & (~)的位运算。
5         System.out.println("andNot = " + bi.andNot(bi));
6         //相当于 | 的位运算
7         BigInteger bi2 = new BigInteger(bytes);
8         System.out.println("or = " + bi2.or(bi2));
9         //相当于 ~ 的位运算
10         BigInteger bi3 = new BigInteger(bytes);
11         System.out.println("not = " + bi3.not());
12         //相当于 & 的位运算
13         BigInteger bi4 = new BigInteger(bytes);
14         System.out.println("and = " + bi4.and(bi4));
15         //相当于 ^ 的位运算
16         BigInteger bi5 = new BigInteger(bytes);
17         System.out.println("xor = " + bi5.xor(bi5));
18     }
19     /*    输出结果如下:
20         andNot = 0
21         or = 65536
22         not = -65537
23         and = 65536
24         xor = 0
25     */

  ⑤ 移位运算:

 1     public static void main(String args[]) {
2 byte[] bytes = new byte[] { 0x1, 0x00, 0x00 };
3 BigInteger bi = new BigInteger(bytes);
4 System.out.println(bi);
5 //右移一位
6 System.out.println("after shift right is " + bi.shiftRight(1));
7 //左移3位
8 System.out.println("after shift left is " + bi.shiftLeft(3));
9 //翻转第三位,既如果第三位(0 based)为0,则翻转为1,反之翻转为0.
10 //翻转之前:10000000000000000
11 //翻转之后:10000000000001000
12 bi = bi.flipBit(3);
13 System.out.println("after flip is " + bi);
14 //将第三位的bit清0
15 //clear之前:10000000000001000
16 //clear之后:10000000000000000
17 bi = bi.clearBit(3);
18 System.out.println("after clear is " + bi);
19 //将第三位设置为1
20 //set之前:10000000000000000
21 //set之后:10000000000001000
22 bi = bi.setBit(3);
23 System.out.println("after set is " + bi);
24 System.out.println("The binary result for bi is " + bi.toString(2));
25 System.out.println("The test result for BIT 2 is " + bi.testBit(2));
26 System.out.println("The test result for BIT 3 is " + bi.testBit(3));
27 }
28 /* 输出结果如下:
29 65536
30 after shift right is 32768
31 after shift left is 524288
32 after flip is 65544
33 after clear is 65536
34 after set is 65544
35 The binary result for bi is 10000000000001000
36 The test result for BIT 2 is false
37 The test result for BIT 3 is true
38 */

  时区

  如果你的产品面向全世界的每一个角落,或者说你接到外包项目可能来自多个不同的国家,那么你的程序将会面临时区问题。

  ① 基于不同时区设置本地时区的Calendar

 1     public static void main(String args[]) {
2 //获取基于日本时区的Calendar对象。
3 Calendar japanCal = new GregorianCalendar(TimeZone.getTimeZone("Japan"));
4 japanCal.set(Calendar.HOUR_OF_DAY, 10); // 0..23
5 japanCal.set(Calendar.MINUTE, 0);
6 japanCal.set(Calendar.SECOND, 0);
7 //本地时区为北京时区
8 Calendar local = new GregorianCalendar();
9 local.setTimeInMillis(japanCal.getTimeInMillis());
10 int hour = local.get(Calendar.HOUR);
11 int minutes = local.get(Calendar.MINUTE);
12 int seconds = local.get(Calendar.SECOND);
13 System.out.println("Hours = " + hour + "\tMinutes = " + minutes
14 + "\tSeconds = " + seconds);
15 }
16 /* 输出结果如下:
17 Hours = 9 Minutes = 0 Seconds = 0
18 */

  和预想的一样,我们通过日本时区设置时间后,在通过该Calendar来设置本地时区的Calendar,结果是得到正确的本地时间,换句话说,时区参与了时间的计算。因此可以说,Calendar对象在生成小时部分的时间时,会结合当时的时间和本地的时区来构造该部分,当时区切换时,Calendar会根据初始的时区、初始的时间和当前的时区来进行推算并给出结果。

  ②获取本地时区和所有可用时区:

1     public static void main(String args[]) {
2         //获取本地时区
3         Calendar now = Calendar.getInstance();
4         TimeZone timeZone = now.getTimeZone();
5 System.out.println("Current TimeZone is : " + timeZone.getDisplayName());
6         //获取系统当前所有可用的时区
7         String[] availableTimezones = TimeZone.getAvailableIDs();
8         for (String timezone : availableTimezones) {
9           System.out.println("Timezone ID = " + timezone);
10         }
11     }
12     /*    输出结果如下:
13         Current TimeZone is : 中国标准时间
14         Timezone ID = Etc/GMT+12
15         Timezone ID = Etc/GMT+11   
16         ... ...
17     */
0
相关文章