1、了解包装类
Java
中预定义了八种基本数据类型,包括:byte
,int
,long
,double
,float
,boolean
,char
,short
。基本类型与对象类型最大的不同点在于,基本类型基于数值,对象类型基于引用。
例如有一个方法 f() ,它的参数分别是对象类型 和 基本类型:
void f(Object obj){ //参数引用类型,保存的是内存地址 } f(123){ //基本类型 }
基本类型基于数值,所以基本类型是没有类而言的,是不存在类的概念的,也就是说,变量只能存储数值,而不具备操作数据的方法。
对象类型则截然不同,变量实际上是某个类的实例,可以拥有属性方法等信息,不再单一的存储数值,可以提供各种各样对数值的操作方法,但代价就是牺牲一些性能并占用更多的内存空间。
Java
中提供了哪些「包装类型」来弥补「基本类型」不具备面向对象思想的劣势呢?看下图:
java.lang.Number
这里需要提到 java.lang.Number
,它是所有数值类的父类,其直接子类包括:Byte
、Short
、Integer
、Long
、Float
、Double
、BigDecimal
、BigInteger
。
这些类取出内部封装的基本类型值的方法很简单也很好记:byteValue()
、shortValue()
、intValue()
、longValue()
、floatValue()
、doubleValue()
其他使用方法也基本相同,下面我们以 Integer 和 Double 为例具体讲一讲
2、Integer
首先需要明确一点的是,既然 Integer
是 int
的包装类型,那么必然 Integer 也能像 int 一样存储整型数值。有兴趣的同学可以看看源码。
Integer
类的内部定义了一个私有字段 value
,专门用于保存一个整型数值,整个包装类就是围绕着这个 value 封装了各种不同操作的方法:
创建对象
Integer i1 = 21; Integer i2 = Integer.valueOf("21");
自动拆装箱
所谓「拆箱」就是指,包装类型转换为基本类型的过程,而所谓的「装箱」则是基本类型到包装类型的过程。
Integer integer = new Integer(21);//装箱 int num = integer.intValue();//拆箱
自从 jdk1.5 以后,引入了自动拆装箱的概念,上述代码可以简化成如下代码:
Integer integer = 21;//装箱 int num = integer;//拆箱
我们来进行分析一下。
自动装箱
Integer integer = 21;
给一个 Integer
类型的对象不能直接赋一个基本类型值,integer
保存的是一个内存地址。21 自动封装成一个对象,把这个对象的地址赋值给 integer
。这个对象是自动创建的,是自动装箱。在程序中编译成:Integer integer = Integer.valueOf(21);
自动拆箱
int num = integer
; 定义一个 int 类型变量,num 应该直接存一个值,integer 保存的是一个内存地址。integer 自动取出对象中的值,然后把值赋值给 num。系统为我们执行了:int num = integer.intValue();
拆装箱是需要方法调用的,耗资源,所以我们的程序中应当尽量避免大量的「拆装箱」操作。
自动拆箱要当心 null 值
我们看以下程序:
public class Main { public static void main(String[] args) { int j = 0; List<Integer> list = new ArrayList<>(); list.add(3); list.add(null); for (int i : list) { j += i; } System.out.println(j); } }
运行时会报空指针
所以在获取到值有可能为空要装箱的时候,一定要加上 null 值的校验。所以可以把程序改为:
程序结果为:
3
面试题1
Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200; System.out.println(i1==i2); System.out.println(i3==i4);
输出结果:
true
false
Integer
类中,存在 Integer
实例缓存数组,范围:-128 - 127。如果在自动装箱的时候给局部变量的int型值是在上面的范围之中,如果是范围内的值,就使用存在的缓存对象;如果不是范围内的值,会新建对象。
面试题2
Integer i1 = new Integer(21); Integer i2 = new Integer(21); System.out.println(i1 == i2); System.out.println(i1.equals(i2));
输出结果:
false
true
如果new
就会在堆内存开辟空间,new两次就开辟两段空间,两段空间地址值一定不一样。不推荐这么写,过时了。
方法
1、从 Number 继承的 6 个方法
byteValue()
、shortValue()
、intValue()
、longValue()
、floatValue()
、doubleValue()
2、字符串解析成 int
Integer.parseInt("255");
//将字符串转换为 int 类型的数值,按十进制解析成 255Integer.parseInt("11111111", 2)
//按二进制解析成 255Integer.parseInt("377",8);
//按八进制解析成 255Integer.parseInt("ff", 16);
//按十六进制解析成 255
3、进制转换
Integer.toBinaryString(255);
//将数字转成二进制,解析成"11111111"Integer.toOctalString(255);
//将数字转换成八进制,解析成"377"Integer.toHexString(255);
//将数字转换成十六进制,解析成"ff"
完整程序
System.out.println("i1:" + Integer.parseInt("255")); System.out.println("i2:" + Integer.parseInt("11111111", 2)); System.out.println("i3:" + Integer.parseInt("377", 8)); System.out.println("i4:" + Integer.parseInt("ff", 16)); System.out.println("s1:" + Integer.toBinaryString(255)); System.out.println("s2:" + Integer.toOctalString(255)); System.out.println("s3:" + Integer.toHexString(255));
输出结果
255
255
255
255
11111111
377
ff
3、Double
Double
类在对象中包装了一个基本类型 double
的值。Double 类对象包含一个 double
类型的字段。此外,该类还提供了多个方法,可以将 double
类型与 String
类型相互转换,同时 还提供了处理 double
类型时比较常用的常量和方法。
创建对象
Double d1 = 21d; Double d2 = Double.valueOf("21");
方法
1、从Number类继承的6个方法,同上
2、将数字字符串转换为 Double 数值 Double.parseDouble("3.14");
3、判断浮点数特殊值Double.isInfinite(double d):
如果此对象表示的值是正无穷大或负无穷大,则返回 true;否则返回Double.isNaN(double d):
如果此 Double 值是一个非数字值,则返回 true,否则返回 false
Infinity:无穷大 NaN:not a number
4、BigDecimal
浮点数的运算是不精确的,我们看以下运算
System.out.println(2 - 1.9); System.out.println(4.35 * 100);
运算结果:
那为什么会出现这种情况呢?
因为不论是 float
还是 double
都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度。究其根本原因是,十进制值通常没有完全相同的二进制表示形式,十进制数的二进制表示形式可能不精确。只能无限接近于那个值。
BigDecimal
的作用就是做精确的浮点运算
构造方法
public BigDecimal(double val) 将double表示形式转换为BigDecimal *不建议使用 public BigDecimal(int val) 将int表示形式转换成BigDecimal public BigDecimal(String val) 将String表示形式转换成BigDecimal * 推荐使用
参数类型为 double
的构造方法的结果有一定的不可预知性。所以通常情况下不使用。
String
构造方法是完全可预知的:写入 newBigDecimal(“0.1”),
将创建一个 BigDecimal
,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用 String
构造方法。
当 double
必须用作 BigDecimal
的源时,请使用 Double.toString(double
) 转成String
,再使用 String
构造方法。或使用 BigDecimal
的静态方法 valueOf
。
举例:使用 double 做构造参数的正确使用
如下程序中 bd1 展示了 参数类型为 double
的构造方法的的不可预知性,db2 展示了 String
的构造方法,bd3、bd4 展示了正确使用 double
做为参数的构造方法。
BigDecimal bd1 = new BigDecimal(1.9); BigDecimal bd2 = new BigDecimal("1.9"); BigDecimal bd3 = BigDecimal.valueOf(1.9); BigDecimal bd4 = new BigDecimal(Double.toString(1.9)); System.out.println("db1:" + bd1); System.out.println("db2:" + bd2); System.out.println("db3:" + bd3); System.out.println("db4:" + bd4);
运行结果:
方法
add(BigDecimal bd)+
保留位数,舍入方式)
subtract(BigDecimal bd)-
multiply(BigDecimal bd)*
divide(BigDecimal bd)/
divide(BigDecimal bd,setScale(保留位数,舍入方式)
舍入运算,运算结果会封装成新的大数字对象返回
举例:实现本节开头的精确运算
BigDecimal bd1 = new BigDecimal("2"); BigDecimal bd2 = new BigDecimal("1.9"); System.out.println("2 - 1.9 = " + bd1.subtract(bd2)); BigDecimal bd3 = new BigDecimal("4.35"); BigDecimal bd4 = new BigDecimal("100"); System.out.println("4.35 * 100 = " + bd3.multiply(bd4));
运行结果:
举例:四舍五入
BigDecimal bd = BigDecimal.valueOf(2.345); double result = bd.setScale(2, RoundingMode.HALF_UP).doubleValue(); System.out.println("result:" + result);
运行结果:
举例:计算降落距离
System.out.println("输入降落时间"); double t = new Scanner(System.in).nextDouble(); //1/2*9.8*t*t BigDecimal a = BigDecimal.valueOf(0.5); BigDecimal b = BigDecimal.valueOf(9.8); BigDecimal c = BigDecimal.valueOf(t); double result = a.multiply(b).multiply(c.pow(2)).doubleValue(); System.out.println("降落距离:" + result + "米");
运行结果:
5、BigInteger
作用:做超大整数运算
在 Java中,由CPU原生提供的整型最大范围是 64 位 long 型整数。使用 long 型整数可以直接通过 CPU 指令进行计算,速度非常快。
如果我们使用的整数范围超过了 long 型怎么办?这个时候,就只能用软件来模拟一个大整数。java.math.BigInteger
就是用来表示任意大小的整数。
我们通过一个例子就可以了解它的使用。
举例:计算阶乘
public class Main { public static void main(String[] args) { System.out.println("输入数字来计算阶乘:"); int number = new Scanner(System.in).nextInt(); System.out.println("阶乘结果:" + f(number)); } private static String f(int number) { //超大整数运算 BigInteger bd = BigInteger.valueOf(number); for (int i = number - 1; i >= 1; i--) { BigInteger bi = BigInteger.valueOf(i); bd = bd.multiply(bi); } return bd.toString(); } }
运行结果:
方法
BigInteger abs()
返回大整数的绝对值BigInteger add(BigInteger val)
返回两个大整数的和BigInteger and(BigInteger val)
返回两个大整数的按位与的结果BigInteger andNot(BigInteger val)
返回两个大整数与非的结果BigInteger divide(BigInteger val)
返回两个大整数的商double doubleValue()
返回大整数的double类型的值float floatValue()
返回大整数的float类型的值BigInteger gcd(BigInteger val)
返回大整数的最大公约数int intValue()
返回大整数的整型值long longValue()
返回大整数的long型值BigInteger max(BigInteger val)
返回两个大整数的最大者BigInteger min(BigInteger val)
返回两个大整数的最小者BigInteger mod(BigInteger val)
用当前大整数对val求模BigInteger multiply(BigInteger val)
返回两个大整数的积BigInteger negate()
返回当前大整数的相反数BigInteger not()
返回当前大整数的非BigInteger or(BigInteger val)
返回两个大整数的按位或BigInteger pow(int exponent)
返回当前大整数的exponent次方BigInteger remainder(BigInteger val)
返回当前大整数除以val的余数BigInteger leftShift(int n)
将当前大整数左移n位后返回BigInteger rightShift(int n)
将当前大整数右移n位后返回BigInteger subtract(BigInteger val)
返回两个大整数相减的结果byte[] toByteArray(BigInteger val)
将大整数转换成二进制反码保存在byte数组中String toString()
将当前大整数转换成十进制的字符串形式BigInteger xor(BigInteger val)
返回两个大整数的异或
到此这篇关于JAVA基本类型包装类 BigDecimal BigInteger
的使用的文章就介绍到这了,更多相关JAVA BigDecimal、BigInteger 的使用内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://juejin.cn/post/7000211953922605070