基本数据类型和包装类
基本数据类型和包装类如下所示:
基本类型 包装类 int java.lang.Integer。父类为java.lang.Number long java.lang.Long。父类为java.lang.Number double java.lang.Double。父类为java.lang.Number char java.lang.Character。父类为java.lang.Object boolean java.lang.Boolean。父类为java.lang.Object byte java.lang.Byte。父类为java.lang.Number float java.lang.Float。父类为java.lang.Number short java.lang.Short。父类为java.lang.Number 8种数据类型的包装类除了Character和Boolean之外,都是继承自Number类
自动装箱与自动拆箱
在JDK1.5及以后,增加了自动装箱与拆箱的新特性。如下所示:
public class Test1 { public static void main(String[] args) { Integer x = 1; //自动装箱 int y = x; //自动拆箱 } }
自动装箱
装箱就是将基本数据类型转换为包装类型。如下所示:
Integer x = 1; 会执行如下代码: Integer x = Integer.valueOf(1);
自动拆箱
拆箱就是将包装类型转换位基本数据类型,如下所示:
int y = x; 会执行如下代码: int y = x.intValue();
注意事项
- 装箱操作会创建对象,频繁的装箱操作会消耗许多内存,影响性能,所以可以避免装箱的时候应该尽量避免。
- NullPointerException空指针异常
Integer x = null; int b = x; //会报NullPointerException异常
- 当 "=="运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象;而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。
- 对于包装器类型,equals方法并不会进行类型转换。
- Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。
1.第一种方式不会触发自动装箱的过程;而第二种方式会触发; 2.在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。 案例分析1
如下所示:
public class Test4 { public static void main(String[] args) { int a = 100; Integer b = 100; System.out.println(a == b); Integer c = 100; Integer d = 100; System.out.println(c == d); Integer e = 200; Integer f = 200; Integer.valueOf(20); System.out.println(e == f); } } 结果为: true true false
分析:
- 第1段代码,基础类型a与包装类b进行==比较,这时b会拆箱,直接比较值,所以会打印true
- 第2段和第3段代码,输出结果表明c和d指向的是同一个对象,而e和f指向的是不同的对象。故打印true和false。
Integer类的valueOf方法源码如下:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
可以看到,这里的实现并不是简单的new Integer,而是用IntegerCache做一个cache,cache的range是可以配置的。IntegerCache源码如下:
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
这是IntegerCache静态代码块中的一段,默认Integer cache 的下限是-128,上限默认127,可以配置,所以到这里就清楚了,在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。
在上面当赋值100给Integer时,刚好在这个range内,所以从cache中取已经存在的Integer对象并返回,所以二次返回的是同一个对象,所以==比较是相等的;当赋值200给Integer时,不在cache 的范围内,所以会new Integer并返回,当然==比较的结果是不相等的。
注意:Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的,故会有一样的效果。
如Long类的valueOf源码如下:
public static Long valueOf(long l) { final int offset = 128; if (l >= -128 && l <= 127) { // will cache return LongCache.cache[(int)l + offset]; } return new Long(l); }
案例分析2
public class Test5 { public static void main(String[] args) { Boolean b1 = false; Boolean b2 = false; Boolean b3 = true; Boolean b4 = true; Double d1 = 100.0; Double d2 = 100.0; System.out.println(d1 == d2); Double d3 = 200.0; Double d4 = 200.0; System.out.println(d3 == d4); } } 结果为: false false
Double类的valueOf源码如下:
public final class Double extends Number implements Comparable<Double> { ... public static Double valueOf(String s) throws NumberFormatException { return new Double(parseDouble(s)); } public static Double valueOf(double d) { return new Double(d); } public Double(double value) { this.value = value; } }
从上面可以看出,在某个范围内的整型数值的个数是有限的,而浮点数却不是。
注意:Double、Float的valueOf方法的实现是类似的, 故也会有一样的效果。
案例分析3
public class Test { public static void main(String[] args) { Boolean b1 = false; Boolean b2 = false; System.out.println(b1 == b2); Boolean b3 = true; Boolean b4 = true; System.out.println(b3 == b4); } } 结果: true true
Boolean类的valueOf源码如下:
public final class Boolean implements java.io.Serializable, Comparable<Boolean>{ public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); ... public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); } public static Boolean valueOf(String s) { return parseBoolean(s) ? TRUE : FALSE; } }
可以看到,TRUE和FALSE是两个静态成员属性,这就是为什么输出两个true的原因了。
BigDecimal
double和flaot在计算时会有精度的丢失,因此在需要精确计算时,使用BigDecimal。 如下所示:
double d1 = 2.01; double d2 = 0.01; double d3 = d1 - d2; System.out.println(d3); 结果值为:1.9999999999999998
使用
BigDecimal位于java.math包中。使用如下所示:
BigDecimal x = new BigDecimal("2.01"); BigDecimal y = new BigDecimal("0.01"); BigDecimal z = x.subtract(y); //做减法运算 System.out.println(z); //打印结果值为2.00,默认调用z.toString
常用API
add 做加法运算 subtract 做减法运算 multiply 做乘法运算 divide 做除法运算
BigInteger
概念
用于int和long取值范围有限,故有BigInteger。BigInteger位于java.math包下,可以描述一个无穷大的整数,理论上BigInteger的储存值范围只受内存的限制。
使用
API
参考:
https://www.jianshu.com/p/bbe6bffcb03b
https://www.cnblogs.com/dolphin0520/p/3780005.html