基本数据类型
基本类型 | 大小 | 最小值 | 最大值 | 包装器类型 |
boolean | -- | -- | -- | Boolean |
char | 8 bits | -128 | 127 | Character |
byte | 16bits | -2^15 | 2^15-1 | Byte |
short | 16bits | -2^15 | 2^15-1 | Short |
int | 32bits | -2^31 | 2^31-1 | Integer |
long | 64bits | -2^63 | 2^63-1 | Long |
float | 32bits | IEEE754 | IEEE754 | Float |
double | 64bits | IEEE754 | IEEE754 | Double |
void | -- | -- | -- | Void |
Java非类成员变量基本数据类型,即在类方法中声明使用的基本数据类型,它存储在堆栈(stack)上。Java对象存储在堆(heap)上,对象的引用存储在堆栈上,我们在程序里面使用的所有对象变量只是对象的引用。每个基本数据类型都有一个对应的包装类,包装类是对基本数据类型的封装,包含了一些有用的方法,如字符串和基本数据类型的转换。基本数据类型无法在堆上创建对象,
class SomeClass{
public void someMethod(){
//下面的代码是非法的
int a = new int;
}
}
如果想在堆上创建一个int变量,可以通过int的包装类Integer来实现。
class SomeClass{
public void someMethod(){
//使用int包装类,在堆上存储Int
Integer a = new Integer(10);
}
}
Java作为纯面向对象语言,为什么会需要基本数据类型呢?
每个对象都需要在堆(heap)上分配内存来存储对象,对象的大小(对象在堆上占用的空间)由对象的成员变量大小来确定,对象的成员变量分为基本数据类型和对象引用,基本数据类型和对象引用的大小是固定的,通过对象的成员变量大小就可以计算出对象的大小。所以Java基本类型的作用之一就是用来确定对象的大小。
为什么不使用基本数据类型的包装类来替代基本数据类型?
理论上说是可以使用包装类来代替基本类型的,但是有一个效率问题。Java的对象都是存储在堆(heap)区,而类方法里面声明使用的基本数据类型变量存储在栈(stack)上,栈上分配和释放内存的效率比堆分配和释放内存的效率高很多,所以如果使用包装类替代基本数据类型会影响程序的效率。
class TestClass{
public void doSomething(){
int a = 10;
Integer b = 20;
}
}
上面的代码中变量a在栈上分配内存,变量b在堆上分配内存,在栈上分配内存效率高的原因可以通过汇编语言代码数量来说明:
sub esp,4 ;在栈上分配4个字节的空间
mov dword [esp], 10 ;初始化变量
add esp, 4 ;释放内存
三行汇编代码就可以在栈上实现内存分配、初始化和释放内存。堆上分配内存则是通过操作系统调用来实现,如c语言里面调用malloc/free函数实现内存分配和内存释放,由于堆内存分配涉及到操作系统内存管理,其汇编代码要远远多于在栈上分配内存的汇编代码,所以栈上分配内存的效率比堆分配内存高。
为什么基本数据类型的长度会是8位、16位、32位、64位?
每一门编程语言最终都要翻译成CPU可以识别的机器码,而CPU通过寄存器来进行算术逻辑运算,即把需要CPU处理的数据放到寄存器里面再进行计算,CPU的寄存器有8位(如ah)、16位(如ax)、32位(如eax)、64位(如rax),如果编程语言基本数据的长度刚好是CPU寄存器支持的数据长度,则编程语言设计更简单且效率更高,因为不用增加两种数据长度之间的转换操作。