Java 基本数据类型与包装类

介绍

本文主要介绍基本数据类型相关概念、自动拆装箱机制和可能遇到的问题阐述。

基本概念

1. 8 种基本数据类型,具体可以分为下面 3 类:

  • 数值型
    • 整数型:byte、short、int、long
    • 浮点型:float、double
  • 字符型:char
  • 布尔型:boolean
基本数据类型长度默认值
byte字节、1 byte 就是 1 个字节,8 位二进制,-128 ~ 1270
short2 字节,16 位,-2^15 ~ 2^15 - 10
int4 字节,32 位,-2^31 ~ 2^31 - 10
long8 字节,64 位,-2^63 ~ 2^63 -10
float4 字节,32 位;最高位符号位,8 位指数,23 位做基数0.0
double8 字节,64 位,最高位符号位,11 位做指数,52 位做基数0.0
char2 字节,单一的 16 位 Unicode 字符,最小值是 ‘\u0000’(即为0),最大值是 ‘\uffff’(即为65,535),可以当整数来用,它的每一个字符都对应一个数字‘\u0000’
booleanfalse

数据类型是程序设计语言描述事物、对象的方法。Java数据类型分为内置类型和扩展类型两大类。内置类型就是 Java 语言本身提供的基本数据类型,比如,整型数,浮点数,字符,布尔值等等。而扩展类型则是Java语言根据基本类型扩展出的其他类型,Java要求所有的扩展类型都必须包括在类定义里面,这就是Java为什么是面向对象编程语言的原因。 Java/数据类型

2. 包装类:数值型包装类继承于 Number 类,而 Boolean、Character 自己对基本类型数据进行了封装。

  • Byte,public final class Byte extends Number implements Comparable
  • Short,public final class Short extends Number implements Comparable
  • Integer
  • Long
  • Float
  • double
  • Character
  • Boolean

3. 为什么需要包装类?

  • Java 是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。比如,在集合类中,我们是无法将 int 、double 等类型放进去的。因为集合的容器要求元素是 Object 类型。

  • 为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。

一些操作

1. 基本数据类型与包装类型的转换

1
2
3
4
5
int i = 1;
Integer a = Integer.valueOf(i);

Integer b = new Integer(1);
int j = b.intValue();

基本数据类型 -> 包装类型: valueOf 方法;
包装类型 -> 基本数据类型: xxxValue 方法

2. 自动拆装箱机制

Java 1.5 引入自动装箱和拆箱机制,即将基本数据类型与对应的包装类型进行自动转换,自动拆装箱的实现就是应用的 valueOf 方法与 xxxValue 方法。

1
2
3
4
5
List<Integer> integerList = new ArrayList<Integer>();
integerList.add(1); // 自动装箱,集合声明的元素为 Integer 类型,但可以直接添加 int 类型数据

Integer a = new Integer(1);
int b = a; // 自动拆箱,一个 Integer 对象也可直接赋值给 int 类型数据

一些问题

1. boolean 类型数据大小

Oracle Java 文档指出,boolean 类型数据表示一个 bit 位的信息,但是其大小并不是确定的(The boolean data type has only two possible values: true and false. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its “size” isn’t something that’s precisely defined.)

后来有人做了实验,定义很多个 boolean 类型数据和 int 类型数据,输出它们占用的空间,发现 int 类型数据占用内存大概是 boolean 类型数据的 4 倍,得到 boolean 类型数据大小为 1 字节的结论。

Stack Overflow 上面也有相关讨论,指出单个 boolean 类型数据占用 1 bit,而 boolean 数组每个元素占用 1 字节。

总而言之,boolean 数据类型大小定义,占用 1 bit 或 1 字节并不能一概而论,要看具体场景。

The Java™ Tutorials

Java中boolean到底占几个字节

Stack Overflow 参考

3. 基本数据类型缓存机制

1
2
3
4
5
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2); // true
System.out.println(f3 == f4); // false
System.out.println(f1.equals(f2)); // true
System.out.println(f3.equals(f4)); // true

在自动装箱的时候,JVM 会缓存 -128 ~ 127 之间的 int 值,所以当该 int i >= -128 && i <= 127 时,会直接返回已缓存的 Integer 对象,否则新建一个 Integer 对象。

1
2
3
4
5
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

f1 == f2 返回 true ,是因为 Integer f1 = 100 发生了自动装箱操作。

f3 == f4 返回 false,是因为 150 不在那个缓存区间,所以返回的是新的对象,所以不相等。

4. 三目运算符引发的空指针异常

1
2
3
4
Map<String,Boolean> map =  new HashMap<String, Boolean>();
Boolean b = (map!=null ? map.get("test") : false); // 抛出 NullPointerException

Boolean b = (map!=null ? map.get("test") : Boolean.FALSE); // 正确做法,都转换为对象,就不会发生拆箱操作

三目运算符,当第二个参数和第三个参数是基本类型和对象时,会对对象进行拆箱操作,那么 map.get(“test”) 转换为 map.get(“test”).booleanValue(),由于 map.get(“test”) 为 null,而 null.booleanValue() 就会抛出空指针异常。

正确的做法就是将三目运算符第二个参数和第三个参数的类型一致即可。

自动拆箱导致空指针异常

5. void 是否是基本数据类型?

Void 类是一个不可实例化的占位符类,它持有对 Java 关键字 void 的 Class 对象的引用。

值类型或者引用类型的数据不同,表现在内存的分配方式,由于 void 不能 new 出对象,也就不能在中分配值,那就是一开始在中分配好空间了,所以这样也可以说它是基本数据类型。

不过绝大部分场合说 8 种是没有问题的。

Java中Void是基本类型吗?基本类型是8种还是9种?

JDK 中文在线

博客参考

一文读懂什么是Java中的自动拆装箱

Java的自动拆装箱