1.自动装箱拆箱
自动装箱和拆箱就是将基本类型和包装类进行自动的互相转换。JDK1.5后,将自动装箱(autoboxing)和拆箱(unboxing)引入java中。
2.1自动装箱和自动拆箱
基本类型数据处于需要对象的环境中时,会自动转为“对象”,这就称为自动装箱。
我们以Integer为例:在JDK1.5以前,这样的代码 Integer i = 5 是错误的,必须要通过Integer i = new Integer(5)
这样的语句来实现基本数据类型转换成包装类的过程;而在JDK1.5以后,Java提供了自动装箱的功能,因此只需Integer i = 5
这样的语句就能实现基本数据类型转换成包装类,这是因为JVM为我们执行了Integer i = Integer.valueOf(5)
这样的操作,这就是Java的自动装箱。
【示例】自动装箱案例
Integer i1 = 100; // 自动装箱
// 相当于编译器自动为您作以下的语法编译:
Integer i2 = Integer.valueOf(100); // 调用的是valueOf(100),而不是new Integer(100)
通过自动装箱特性,我们可以用Object数组来存放基本数据类型数据。
// 存放基本数据类型的数组(自动装箱)
Object[] arr = {11.1, 18, 12, 11.1};
每当需要一个值时,对象会自动转成基本类型数据, 没必要再去显式调用intValue、doubleValue()等转型方法,这就是自动拆箱。
自动装箱过程是通过调用包装类的valueOf()方法实现的,而自动拆箱过程是通过调用包装类的 xxxValue()方法实现的(xxx代表对应的基本数据类型,如intValue()、doubleValue()等)。
【示例】自动拆箱案例
Integer i = 100; // 自动装箱
int j = i; // 自动拆箱
// 相当于编译器自动为您作以下的语法编译:
int j1 = i.intValue();
1.2自动装箱缓存问题
在 JDK1.5 自动装箱时,如果数值在byte(-128-127)范围之内,为了提高效率Integer类会进行缓存处理,不会新创建对象空间而是使用原来已有的空间。当数值超出byte范围之外,就不会对Integer类进行缓存处理了。
Integer类相关源码如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
通过IntegerCache这个静态内部类,实现对-128~127之间的值会进行缓存处理。
【示例】自动装箱缓存案例
Integer a = 12;
Integer b = 12;
// 未超出 byte 范围,新建的对象会进行缓存处理,a和b指向同一块地址
System.out.println(a == b); // 输出:true
// 包装类中的equals方法,只比较的是内容值
System.out.println(a.equals(b)); // 输出:true
Integer c = 128;
Integer d = 128;
// 超出 byte 范围,新建的对象不会进行缓存处理,c和d是指向不同的地址
System.out.println(c == d); // 输出:false
System.out.println(c.equals(d)); // 输出:true
扩展:尝试着模拟实现Integer类。
1.3空指针异常问题
【示例】包装类空指针异常案例
Integer i = null;
int j = i;
执行结果如下图所示:
以上代码运行结果之所以会出现空指针异常,是因为该代码相当于:
// 把null赋值类i变量,是一个合法的操作
Integer i = null;
// 对空对象i执行intValue()方法,抛出空指针异常
int j = i.intValue();
null表示i没有指向任何对象的实体,但作为对象名称是合法的(不管这个对象名称存是否指向了某个对象的实体)。由于实际上i并没有指向任何对象的实体,所以也就不可能操作intValue()方法,这样上面的写法在运行时就会抛出NullPointerException异常。
2.整数进制转换
2.1十进制转别的进制
我们可以通过Integer类提供的静态方法实现进制之间的转换。
包装类 | 方法 | 作用 |
---|---|---|
Integer | static String toBinaryString(int i) | 把十进制转化为2进制 |
Integer | static String toOctalString(int i) | 把十进制转化为8进制 |
Integer | static String toHexString(int i) | 把十进制转化为16进制 |
【示例】十进制转别的进制案例
// 十进制转2进制
System.out.println(Integer.toBinaryString(4)); // 输出:100
// 十进制转8进制
System.out.println(Integer.toOctalString(9)); // 输出:11
// 十进制转16进制
System.out.println(Integer.toHexString(17)); // 输出:11
2.2别的进制转十进制
通过Integer类的static int parseInt(String s, int radix)
方法,把别的进制转化为十进制。
【示例】别的进制转十进制案例
// 2进制转化为十进制
System.out.println(Integer.parseInt("100", 2)); // 输出:4
// 8进制转化为十进制
System.out.println(Integer.parseInt("11", 8)); // 输出:9
// 16进制转化为十进制
System.out.println(Integer.parseInt("1a", 16));; // 输出:26
3. Java大数字运算
3.1 BigInteger类
由于java语言中的long类型表示整数数据范围有限,若希望描述更大的整数数据时,就需要借助java.math.BigInteger
类型加以描述。BigInteger
类属于java.math
包中,因此在每次使用前都要import 这个类。
【示例】BigInteger类的构造方法
// 参数类型为String的构造方法
BigInteger bd = new BigInteger("111111");
// 输出:111111
System.out.println(bd);
一般来说,可以使用BigInteger的构造方法或者静态方法的valueOf()方法把基本类型的变量构建成BigInteger对象。
因为BigInteger所创建的是对象,我们不能使用传统的+、-、*、/、%等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法,方法中的参数也必须是BigInteger的对象。
BigInteger add(BigInteger augend) | 加法运算 |
---|---|
BigInteger subtract(BigInteger subtrahend) | 减法运算 |
BigInteger multiply(BigInteger multiplicand) | 乘法运算 |
BigInteger divide(BigInteger divisor) | 除法运算 |
BigInteger[] divideAndRemainder(BigInteger val) | 求余运算 |
【示例】BigInteger类的数学运算方法
// 实例化两个BigInteger对象
BigInteger d1 = new BigInteger("5");
BigInteger d2 = new BigInteger("2");
// 加法运算
BigInteger addNum = d1.add(d2);
System.out.println("加法运算:" + addNum); // 输出:7
// 减法运算
BigInteger subtractNum = d1.subtract(d2);
System.out.println("减法运算:" + subtractNum); // 输出:3
// 乘法运算
BigInteger multiplyNum = d1.multiply(d2);
System.out.println("乘法运算:" + multiplyNum); // 输出:10
// 除法运算
BigInteger divideNum = d1.divide(d2);
System.out.println("除法运算:" + divideNum); // 输出:2
// 取余运算
BigInteger[] result = d1.divideAndRemainder(d2);
// 输出:商:2 余数:1
System.out.println("商:" + result[0] + " 余数:" + result[1]);
进行传统的+、-、*、/、%等算术运算后,我们可能需要将BigInteger对象转换成相应的基本数据类型的变量,可以使用floatValue(),doubleValue()等方法。
【示例】BigInteger类型转化为基本数据类型
// 实例化两个BigInteger对象
BigInteger d1 = new BigInteger("5");
BigInteger d2 = new BigInteger("2");
// 加法运算
BigInteger addNum = d1.add(d2);
// 把BigInteger类型转化为int类型
int num = addNum.intValue();
System.out.println(num); // 输出:7
// 减法运算
BigInteger subtractNum = d1.subtract(d2);
// 把BigInteger类型转化为double类型
double d = subtractNum.doubleValue();
System.out.println(d); // 输出:3.0
3.2 BigDecimal类
float和double类型的主要设计目标是为了科学计算和工程计算,双精度浮点型变量double可以处理16位有效数,然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。
【示例】浮点型无法精确提供运算结果案例
// 输出结果为:3.0000000000000004E-8
System.out.println(0.00000001 + 0.00000002);
但是商业计算往往要求结果精确,这时候java.math.BigDecimal类就派上大用场啦。BigDecimal由任意精度的整数非标度值和32位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以10的负scale 次幂。
BigDecimal(double val) | 创建一个具有参数所指定双精度值的对象。 |
---|---|
BigDecimal(int val) | 创建一个具有参数所指定整数值的对象。 |
BigDecimal(long val) | 创建一个具有参数所指定长整数值的对象。 |
BigDecimal(String val) | 创建一个具有参数所指定以字符串表示的数值的对象。 |
构造一个浮点型的BigDecimal对象,参数类型为double的构造方法的结果有一定的不可预知性,而String 构造方法是完全可预知的,所以尽量使用参数类型为String的构造函数。
【示例】BigDecimal类的构造方法
// 参数类型为double的构造方法
BigDecimal aDouble = new BigDecimal(1.22);
// 输出:aDouble: 1.2199999999999999733546474089962430298328399658203125
System.out.println("aDouble: " + aDouble);
// 参数类型为String的构造方法,建议使用
BigDecimal aString = new BigDecimal("1.22");
// 输出:aString: 1.22
System.out.println("aString: " + aString);
一般来说,可以使用BigDecimal的构造方法或者静态方法的valueOf()方法把基本类型的变量构建成BigDecimal对象。
因为BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法,方法中的参数也必须是BigDecimal的对象。
BigDecimal add(BigDecimal augend) | 加法运算 |
---|---|
BigDecimal subtract(BigDecimal subtrahend) | 减法运算 |
BigDecimal multiply(BigDecimal multiplicand) | 乘法运算 |
BigDecimal divide(BigDecimal divisor) | 除法运算 |
【示例】BigDecimal类的数学运算方法
// 实例化两个BigDecimal对象
BigDecimal d1 = new BigDecimal("3.0");
BigDecimal d2 = new BigDecimal("2.0");
// 加法运算
BigDecimal addNum = d1.add(d2);
System.out.println("加法运算:" + addNum); // 输出:5.0
// 减法运算
BigDecimal subtractNum = d1.subtract(d2);
System.out.println("减法运算:" + subtractNum); // 输出:1.0
// 乘法运算
BigDecimal multiplyNum = d1.multiply(d2);
System.out.println("乘法运算:" + multiplyNum); // 输出:6.00
// 除法运算
BigDecimal divideNum = d1.divide(d2);
System.out.println("除法运算:" + divideNum); // 输出:1.5
进行传统的+、-、*、/等算术运算后,我们可能需要将BigDecimal对象转换成相应的基本数据类型的变量,可以使用floatValue(),doubleValue()等方法。
【示例】BigDecimal类型转化为基本数据类型
// 实例化两个BigDecimal对象
BigDecimal d1 = new BigDecimal("3.0");
BigDecimal d2 = new BigDecimal("2.0");
// 加法运算
BigDecimal addNum = d1.add(d2);
// BigDecimal类型转化为int类型
int n = addNum.intValue();
System.out.println(n); // 输出:5
// 除法运算
BigDecimal divideNum = d1.divide(d2);
// BigDecimal类型转化为double类型
double d = addNum.intValue();
System.out.println(d); // 输出:5.0
ps:如需最新的免费文档资料和教学视频,请添加QQ群(627407545)领取。