基本数据类型

1. 包装类型

1.1 定义

Java 的包装类型(Wrapper Class)是对基本数据类型的对象表示,用于将基本数据类型(如 intdouble)包装为类对象。包装类存在的主要目的是使基本数据类型能够与 Java 的集合框架(如 ArrayList)等只能操作对象的API兼容。

1.2 基本类型和包装类型的区别

  • 用途:定义一些常用变量或局部变量会使用基本类型;在对象属性,方法参数中会使用包装类型,同时包装类型可用于泛型。
  • 存储方式:基本数据类型的局部变量存放在 Java 虚拟机栈中的局部变量表中,基本数据类型的成员变量(未被 static 修饰 )存放在 Java 虚拟机的堆中。包装类型属于对象类型,存储在堆中。
  • 占用空间:基本数据类型占用空间小。
  • 默认值:成员变量包装类不赋值就是null,基本数据类型有默认值。
  • 比较方式:基本数据类型中,==比较的是数值是否相同;对于包装类型来说,==比较的是对象的内存地址,equals可以比较数值大小。

1.3 包装类型的缓存机制

Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False两种浮点数类型的包装类 Float,Double 并没有实现缓存机制。

1.4 自动装箱与拆箱

1.4.1 定义

自动装箱:将基本数据类型转换为对应的包装类对象。

自动拆箱:将包装类对象自动转换为对应的基本数据类型。

举例:

1
2
Integer i = 10;  //装箱
int n = i; //拆箱

1.4.2 综合理解装箱和包装类缓存机制

下面我们来看一个问题:下面的代码的输出结果是 true 还是 false 呢?

1
2
3
Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);

Integer i1=40 这一行代码会发生装箱,也就是说这行代码等价于 Integer i1=Integer.valueOf(40) 。因此,i1 直接使用的是缓存中的对象。而Integer i2 = new Integer(40) 会直接创建新的对象。

因此,答案是 false

下面是另一个例子

1
2
3
4
5
6
7
8
9
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true, 因为值在缓存范围内(-128 到 127)
System.out.println(a.equals(b)); // true, 比较值

Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false, 超出缓存范围

2. BigDecimal

2.1 为什么浮点数运算的时候会有精度丢失的风险

计算机是二进制的,而且计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。

2.2 如何解决这个问题

使用BigDecimal,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("1.00");
BigDecimal c = new BigDecimal("0.8");

BigDecimal x = a.subtract(c);
BigDecimal y = b.subtract(c);

System.out.println(x); /* 0.2 */
System.out.println(y); /* 0.20 */
// 比较内容,不是比较值
System.out.println(Objects.equals(x, y)); /* false */
// 比较值相等用相等compareTo,相等返回0
System.out.println(0 == x.compareTo(y)); /* true */

BigDecimal 是以字符串或整数形式存储的,所有运算都遵循十进制规则。

3. 超过long整型数据应该如何表示

使用BigInteger,BigInteger 内部使用 int[] 数组来存储任意大小的整形数据。