8种基本数据类型
Java语言有8种基本数据类型,分别用于存储整数、浮点数、字符数据和布尔类型数据。
Java8种基本类型的存储空间和使用场景如下表所示:
int类型
int是最常用的整数类型。一个int类型的变量占用4个字节(32位),
最大表示范围为:-2^31 ~ 2^31-1,即-2147483648~2147483647。
- 关于整数的除法
在Java中,两个整数相除,会舍弃小数的部分,结果也是整数。请看如下代码:
int c = 5/3;
System.out.println(c); // c的值为1
- 整数运算的溢出
两个整数进行运算时,其结果可能会超过整数的范围而溢出,请看如下代码:
int a = 2147483647;
int b = -2147483648;
a = a + 1;
b = b - 1;
System.out.println("a=" + a);
System.out.println("b=" + b);
上述代码运行后的输出结果为:
a=-2147483648
b=2147483647
变量a最初的值为2147483647,是int类型的最大值,加1以后出现了溢出现象,a的值变成了int类型的最小值。而b变量最初赋的值为-2147483648,是int类型的最小值,减1以后出现了溢出现象,b的值变成了int类型的最大值。
long类型
在表示整数时,如果int类型的范围不够,可以使用long型,一个long型的变量占用8个字节(64位),最大表示范围为:-2^63 ~ 2^63-1,即 -9223372036854775808 ~ 9223372036854775807。
当一个直接量超过int类型的最大值时,那要用long类型来表示,如果要表示long直接量,需要以 L 或 l 结尾。请看下列代码:
long a = 10000000000; // 会有编译错误
long b = 10000000000L;
float、double类型
浮点数,就是小数,包括: float和double。
double类型的精度值是float类型的两倍,这正是其名称(双精度)的来由。
- 取值范围
float和double的范围是由指数的位数来决定的。
float的指数位有8位,而double的指数位有11位,分布如下:
float: 1bit(符号位) 8bits(指数位) 23bits(尾数位)
double: 1bit(符号位) 11bits(指数位) 52bits(尾数位)
于是,float的指数范围为-128~+127,
而double的指数范围为-1024~+1023,
并且指数位是按补码的形式来划分的。
其中负指数决定了浮点数所能表达的绝对值最小的非零数;
而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;
double的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308。
- 浮点数的直接量为double类型
默认的浮点直接量为double型,如果需要表示float类型的直接量,需要加“f”或“F”后缀。请看如下代码:
float f1 = 3.14 ;
以上代码,会出现编译错误。3.14是double类型的直接量,如果表示float类型的直接量应该写成3.14f。
- 浮点数存在舍入误差问题
由于浮点数内部用二进制的方式来表示十进制,会存在舍入误差。二进制系统中无法精确的表示1/10,就好像十进制系统中无法精确的表示1/3一样。对于一些要求精确运算的场合会导致代码的缺陷。请看如下代码:
double money = 3.0;
double price = 2.9;
System.out.println(money - price);
上述代码的输出结果为:
0.10000000000000009
查看上述结果,并没有如我们想象的为0.1。如果需要精确的运算可以考虑放弃使用double或float而采用BigDecimal 类来实现。
char类型
字符类型事实上是一个16位无符号整数,这个值是对应字符的编码,Java字符类型采用Unicode字符集编码。Unicode是世界通用的定长字符集,所有的字符都是16位。
字符直接量 可以采用诸如: ‘中’ 的形式,也可以采用其对应的16进制的表示形式,
例如:’ \u4e2d’。
- 对char类型变量赋值
在对char型变量赋值时,可以采用如下三种方式:
字符直接量:形如’A’,变量中实际存储的是该字符的Unicode编码(无符号整数值),一个char型变量只能存储一个字符。
整型直接量:范围在0~65535之间的整数,变量中实际存储的即该整数值,但表示的是该整数值所对应的Unicode字符。
Unicode形式:形如’\u0041’,Unicode字符的16进制形式。
char zhong='疯';
int zhongValue=zhong;
System.out.println(zhongValue);
上述代码的输出结果为:
30127
上述输出结果为0~65535范围的。
另外,如果把0~65535范围内的一个int整数赋给char类型变量,系统会自动把这个int类型整数当成char类型来处理。请看如下代码:
char c=97;
System.out.println(c);
上述代码的输出结果为a。这说明系统自动把整数类型97当成char类型来处理,处理的结果为a,即,97为字母a的unicode码。
- 使用转义字符
对于不方便输出的字符采用转义字符表示,例如:
boolean类型
- boolean类型适用于逻辑运算,表示某个条件是否成立。一般用于程序的流程控制。
- boolean类型只允许取值true或false,true表示条件成立,而false表示条件不成立。
- boolean型变量经常用于存储关系运算的结果,所谓关系运算就是比较两个变量的大小相等等关系。
类型间的转换
//原码 反码 补码
//正数补码:原码
//负数补码:原码 取反 +1
/*补码形式存储
* byte 8位 最大0111 1111 127
* 最小1000 0000 -128
*/
/*
* short:16位 -2^15~2^15-1
* int:32位 -2^31~2^31-1
* long:64位
*/
byte b = 127;
short s = 128;//0000 0000 1000 0000
s = b;//自动类型转换
b = (byte)s;//强制类型转换->只留低8位
System.out.println(b);//127
int i = 2100000000;
//所有的整数直接量/字面量默认都是int类型
//表示long类型 l/L
long l = 21000000000l;
b = (byte)(b + 1);//运算时,会将变量统一为同一种类型
//获得当前系统时间
System.out.println(b);//-128
long time = System.currentTimeMillis();
System.out.println(time);
//计算明天的这个时候 -> 涉及到时间一定要加l
long time2 = 24l*3600*1000*30;
System.out.println(time2);
//获取最大值
//byte -> Byte short-> Short
//int -> Integer long -> Long
System.out.println(Integer.MAX_VALUE);
System.out.println(Long.MAX_VALUE);
System.out.println(Short.MAX_VALUE);
System.out.println(Byte.MAX_VALUE);
System.out.println(Byte.MIN_VALUE);
//精度缺失问题一定会存在,浮点数不能做相等判断
//浮点数的字面量默认double类型
float f = 3.1415926f; //f/F或强转
double d = 3.1415926;
// 1/3=0.333333333333333
double d1 = 5.0 - 4.9;
System.out.println(d1);//0.09999999999999964
/*
* 字符:char 16位 0~2^16-1=65535 2个字节
* UTF-8(国际编码) GBK(中国编码) 字节->字符 = 编码 解码
*
*/
char c = '中';
c = 65;//A
c = '\u4e2d';//0~65535 \u0000~\uffff(Unicode编码)
int a = 017;//15 加0八进制
System.out.println(a);
a = 0xe;//15 加0x十六进制
System.out.println(c);
/*
* boolean类型
*/
boolean b = true;
b = false;
b = 3==1;
System.out.println(b);//false
不同的基本类型直接可以互相转换:
自动类型转换(隐式类型转换):从小类型到大类型可以自动完成。类型的大小关系如下图所示:
强制转换:从大类型到小类型需要强制转换符:(需要转换成的类型)变量。但这样转换有可能会造成精度损失或者溢出。
- 强制转换时的精度丧失和溢出
基本类型之间的相互转换,需要注意的是,强制转换时可能会造成精度的丧失和溢出,请看如下代码:
long l = 1024L * 1024 * 1024 * 4;
int j = (int) l; // 会产生溢出
System.out.println(j); // 结果为:0
上述代码输出的结果为0,是因为在将long类型变量l转换为int类型变量j的时候产生了溢出。另外,请看如下精度丧失的例子:
double pi = 3.141592653589793;
float f = (float) pi; // 会造出精度的损失
System.out.println(f); // 结果为:3.1415927
- 数值运算时的自动转换
多种基本类型参与的表达式运算中,运算结果会自动的向较大的类型进行转化。请看如下示例:
long distance = 10000 * 365 * 24 * 60 * 60 * 299792458L;
上述代码中,有int类型数据和long类型数据,由于有long型的直接量299792458L参与,整个表达式的结果为long。
double change = 800 - 599.0;
上述代码中,由于有double型的直接量599.0参与,整个表达式的结果为 double。
double persent1 = 80 / 100;
上述代码中,结果为0.0。右边都是int型数据,语法运算后的结果也为int类型,结果为0,再赋值给double型,将0转化为 0.0。请对比下面的代码:
double persent2 = 80.0 / 100;
上述代码中,结果为0.8,右边表达式有double型直接量参与,运算结果为double型。
- byte、char、short转换为int的问题
byte、char、short 三种类型实际存储的数据都是整数,在实际使用中遵循如下规则:
1) int直接量可以直接赋值给byte、char和short,只要不超过其表示范围。
2) byte、char、short三种类型参与运算时,先一律转换成int类型再进行运算。请看如下示例代码:
byte b1 = 28;
byte b2 = 20;
byte b3 = b1 + b2;
上述代码在第三行会出现编译错误,原因是b1+b2的结果为int类型。改变上述代码如下:
byte b1 = 28;
byte b2 = 20;
int b3 = b1 + b2;
查看上述代码,会发现不会再出现编译错误。char类型、short类型和byte类型是相似的。