回顾一下前面的一系列文章,java
走进 JDK 之 Floatbash
除了 char
和 double
,基本涵盖了 Java 的全部基本类型。今天就来总结一下基本类型的相关知识。布局
Java 中有 8 种基本类型,以下表所示:post
基本类型 | 大小 | 最大值 | 最小值 | 包装类 | 虚拟机中符号 |
---|---|---|---|---|---|
boolean | - | - | - | Boolean | Z |
char | 16 bits | 65536 | 0 | Character | C |
byte | 8 bits | 127 | -128 | Byte | B |
short | 16 bits | 215-1 | - 215 | Short | S |
int | 32 bits | 231-1 | 231 | Integer | I |
long | 64 bits | 263-1 | -263 | Long | J |
float | 32 bits | 3.4028235e+38f | -3.4028235e+38f | Float | F |
double | 64 bits | 1.7976931348623157e+308 | -1.7976931348623157e+308 | Double | D |
每种基本类型所占的存储空间大小不会随着机器硬件架构的变化而变化,具备良好的可移植性。编码
数值类型有 byte
、short
、int
、long
、float
、double
。其中 byte
、short
、int
、long
是整数类型。float
和 double
是浮点数类型,分别表示单精度和双精度,遵循 IEEE 754
浮点数标准。Java 中全部数值类型都是有符号数,最高位表示符号位。spa
boolean
是布尔类型,只有两个值 TRUE
和 FALSE
,在 JVM
中当作 int
处理,两个值分别为 1
和 0
。
char
是字符类型,为 Unicode
编码。在某些应用场景下,能够把 char
看成无符号数来处理。
对于上面表格中的内容,还有几点须要说明一下:
溢出问题
整数类型都有本身的取值范围,若是强行超出它的范围会怎么样呢?以下面代码:
public void test() {
byte max = Byte.MAX_VALUE;
byte over = (byte) (max + 1);
System.out.println(over);
}
复制代码
打印结果是 -128
,即 Byte.MIN_VALUE
。你能够把值域范围想象成时钟的刻度,最大值是 12 ,最小值是 0 ,已经到了最大值 12 ,你还要再加 1 ,就发生了溢出,又回到了最小值 0 。
栈上大小
在栈上,byte
、short
、boolean
、char
占用的空间和 int
是一致的,都是占一个 slot
。long
和 double
是占用两个 slot
。具体缘由在以前的文章中具体分析过,这里再总结一下:
固然,这仅仅只是针对栈上,对于堆上和数组中分配的基本类型,其大小仍是和表中匹配的。
这块内容在 走进 JDK 之 Boolean 中详细介绍过。操做码是单字节的,最多只有 256 个字节码指令,不可能为每个基本数据类型提供完整的指令支持。大部分的指令都没有支持 byte
、 char
和 short
,boolean
则更惨,没有任何指令支持 boolean
类型。对于这些不支持的指令类型,一概使用 int
的相关指令代替。
对于不肯定的状况,你能够看一下 class 文件中的字节码:
javac Test.java
javap -v Test.class
复制代码
基本全部语言都有基本数据类型,Java 固然也是如此。标榜 万物皆对象
的 Java 为何须要基本数据类型的存在呢?回顾一下你的职业生涯中写过的代码,基本数据类型出现的几率能够说至关之高,基本数据类型是直接存储在栈内存的,而 new
出来的对象是存储在堆内存中的。显然对象占用的内存是高于基本数据类型的。对象在内存中存储的布局能够分为 3 块区域:对象头
、实例数据
、对齐填充
。若是把你的代码中全部基本类型所有替换为其包装类,无疑会占用更多的内存,也下降了运行效率。
就冲那句 万物皆对象
,固然也得有包装类了!开个玩笑而已 ... 基本数据类型占用内存更少,运行速度更快,但它也有办不到的事情,好比我要构造一个包含 int
的 List
集合:
List list = new ArrayList<int>();
复制代码
显然这是无法经过编译的。这里咱们传进去的必须是一个对象,因此基本数据类型还必须得有一个包装类。包装类中包装了基本类型的数值,而且提供了一系列处理数值的方法,就像前面分析的过得源码中各类方法,丰富了基本数据类型的功能。
把基本数据类型转换成包装类的过程叫作装箱。
把包装类转换成基本数据类型的过程叫作拆箱。
在Java SE 5.0 以前,装箱和拆箱须要手动进行。可能 Java 开发者们以为这样实在太不人性化了,一切应该以提升生产力为主,在 Java SE 5.0 中就推出了自动装箱和拆箱。以 Integer
为例:
Integer i = 10; //自动装箱
int b = i; //自动拆箱
复制代码
咱们已经解析过 Integer
的源码,不难想象,自动装箱和拆箱必然是调用了包装类的某些方法,javap
看一下字节码:
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: aload_1
7: invokevirtual #3 // Method java/lang/Integer.intValue:()I
复制代码
很明了,以前的代码通过编译器编译,已经改变了模样:
Integer i = Integer.valueOf(10); //装箱
int b = i.intValue(); //拆箱
复制代码
还记得 valueOf()
方法吗?
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
,其余基本数据类型也都是使用相似 valueOf()
和 xxxValue()
方法来进行自动装箱和拆箱的。
如今你应该知道了自动装箱和自动拆箱其实是编译器在里面作了手脚,和 Java 虚拟机并无什么关系。编译器在生成类的字节码时,插入必要的方法调用。虚拟机只是执行这些字节码。
走进 JDK 系列的基本数据类型部分就说到这里了,还有什么疑问的话,欢迎关注个人公众号 秉心说
给我留言。
下一篇是 走进 JDK 之 String
,不出意外的话应该要过几天,String
的内容仍是比较多的,能够先阅读阅读我以前的一篇文章 String 为何不可变? 。
文章首发于微信公众号:
秉心说
, 专一 Java 、 Android 原创知识分享,LeetCode 题解,欢迎关注!