Java的数据类型
对于Java基本数据类型,我将从三个方向进行总结:
1.Java中有哪些数据类型?
基本类型
引用类型
浮点型的存储格式与范围
2.基本数据类型之间的相互转换。
自动类型转换
强制类型转换
3.数据类型的常见面试题。
Java的数据数据类型
Java的数据类型可以分为两类,一类是原始/基本数据类型,一类是引用数据类型。它们的区别在于一个保存的是数值,一个保存的是地址值,但是本质上保存的都是一种值。
Java原始数据类型分为四类八种:
分类 | 基本类型 | 在计算机保存的字节 | 表示的范围 |
整型 | byte(字节型) | 1字节/8位 | -128到127 |
short(短整型) | 2字节/16位 | -32768到32767 | |
int(整型) | 4字节/32位 | -2^31到2^31-1 | |
long(长整型) | 8字节/64位 | -2^63到2^63-1 | |
字符型 | char(字符型) | 2字节/16位 | 0到65535 |
浮点型 | float(单精度) | 4字节/32位 | -3.403E3到3.403E38 |
double(双精度) | 8字节/64位 | -1.798E308到1.798E308 | |
布尔(逻辑)型 | boolean(布尔型) | 1字节/8位 | 仅true或false |
在我们使用基本数据类型定义变量的使用,会考虑数据类型的范围是否能够保存数据,所以有必要对各种数据类型的范围有个比较深刻的了解。尤其是浮点型数据来说。
单精度float的范围:保留8位有效数字,前7位准确。
在计算机的存储方式
1位符号位:表示数据的正负,0为正,1为负
8位指数位:能够表示2^8个数,即范围是0到255,但是实际定义的时候,要对8位指数位的值减去127,所以最后的范围在-127到128。
23位尾数位:表示的是原来的数转换后的尾数部分。
取值范围=符号位(正负1)*2^(指数值-127)*尾数
双精度double的范围:保留17位有效数字,前16位准确。
在计算机的存储方式
1位符号位:表示数据的正负,0为正,1为负
11位指数位:能够表示2^11个数,即范围是0到2047,但是实际定义的时候,要对11位指数位的值减去1023,所以最后的范围在-1023到1024。
52位尾数位:表示的是原来的数转换后的尾数部分
取值范围=符号位(正负1)*2^(指数-1023)*尾数
从取值范围的表达式可以看到,不管是float型还是double型,其范围实际上是由指数上的位数来决定的,所以可以大致的使用极限来确定其范围,因为对于尾数来说,其最大是趋近于1。可以得到下列的大致的范围:
float的最小值:-1 * 2^128 * 1
float的最大值: 1 * 2^128 * 1
即-3.403E3到3.403E38
double的最小值:-1 * 2^1024 * 1
double的最大值: 1 * 2^1024 * 1
即-1.798E308到1.798E308
Java引用数据类型:
在Java中,引用类型的变量非常类似于C语言中的指针,保存的是存储空间的地址值。通过这个地址使引用类型变量指向一个对象。比如常见的数组和对象就是引用数据类型。
其实我们可以发现不管是地址值,还是一个数值,实际上都是一种值,那为什么在java中要进行分类呢?主要原因是基本类型的变量只与自己有关中,表示变量本身的值,而引用类型变量的值,表示本身的同时,这个值还具有指向(意义),和计算机中的堆有联系,通过这个地址值可以找到对应堆中的地址。
Java虚拟机执行main方法() 把main方法加载到栈中,然后并给main方法分配一定的存储空间。
1.在栈中给int型变量sum分配存储空间,并赋值为0,可以看到这个值只有自己有关。
2.而引用类型s保存的是地址值,比如Student s=new Student();首先会在堆中创建new Student()的对象,并把这个对象在堆中的地址值返回赋值给引用类型s,这样引用类型就指向了这个对象。
基本数据类型之间的相互转换
在java中,当把一种基本数据类型变量的值赋给另一种基本类型变量时,就涉及数据转换。下列基本数据类型会涉及数据转换(不包括逻辑类型,boolean不可以和其他数据类型转换,即使是强制类型转换也不行,会报错。这就和C++有所不同,在C++中true可以表示1,false可以表示0)
这些可以转换的基本数据类型精度由低到高排列:
当把级别低的变量的值赋给级别高的变量的时候,系统自动完成数据类型的转换。
从精度图中可以看到,当顺着箭头的方向,可以把低精度的数据类型的变量赋值给精度高的数据类型的变量,程序不会报错,否则就会报错。
这是为什么?或者说为什么会出现这种情况。
这里就和各种数据数据之间的取值范围有关了。
比如:int型数据范围包含了short型、char型、byte型,所以当把这几种数据类型的变量赋值给int型变量,int型变量是可以保存的,所以不会报错。反之,不能保存,报错。
不过这里要注意一点的是,虽然高精度的变量类型范围包含了低精度类型的范围,但是不一定不会精度缺失。
从图中可以看出,虽然long型的范围在float型的范围内,但是在赋值后值的大小实际上已经发生了改变。
X6 214748364755222L
Y6 214748365000000
这个过程与float型所保留的有效数字有关,float型最多保存8位有效数字,所以虽然long型的范围在float型的范围内,但是float也只能取其中的8位,所以当long的位数大于八的话,就可能出现精度缺失。
当把级别高的变量的值赋值给级别低的变量时,必须使用强制类型转换运算。
上面我们说过,高精度的范围大于低精度的范围,直接把高精度的值直接赋给低精度的变量的话,低精度的范围是不够的,所以不能直接赋值。
但是Java提供了强制类型转换,可以把高精度的值强制转换成低精度的值,实际上就是把高精度的值中截取一部分后的剩余的部分。当然,截取后的数值可能发生了变化。
格式为:(类型名)要转换的值。
int型转换成byte型:其他类型之间的转换是相似的。
这里要注意原码、反码、补码的转换。
关于基本数据类型的面试题:
1.Java中3*0.1==0.3将会返回什么?true还是false?
答:false,因为浮点数不能完全精确的表示出来,一般都会有精度损失。
//整型-----保存的准确值
//浮点型------保存的是近似值
//所以转换的时候可能有精度损失。
2.java中float f=3.4;是否正确?
答:不正确,在java中整数常量默认为int型,浮点数常量默认为双精度类型,将双精度类型(double)赋值给单精度类型(float)属于把高精度赋值给低精度变量,会造成精度损失,因此需要强制类型转换float f =(float)3.4;或者写成float f=3,4f;才可以。
3.能否在不进行强制转换的情况下将一个double值赋值给long类型的变量?
答:不行,我们不能再没有强制类型转换的前提下将一个double值赋值给long类型的变量,因为double类型的范围比long类型更广,所以必须要进行强制转换。
4.java的switch语句能否作用byte类型变量上,能否作用在long类型变量上,能否作用在String类型变量上。
答:由于switch(表达式)中的表示式默认的是int型数值,byte的存储范围小于int,所以可以向int类型隐式转换,所以switch可以作用在byte类型变量上,由于long类型的存储范围大于int,不能向int进行隐式转换,只能强制类型转换,所以switch不可以作用在long类型变量上;同时对于String类型来说,在java1.7版本之前不可以,1,7版本之后是可以的。
最后,这是我关于数据类型的一些理解,可能有一些错误。以后有了更深入的了解,会重新对博客进行修改。