Java基本数据类型
八种基本数据类型常识
|
|
|
|
|
| |
---|---|---|---|---|---|---|
整型 | byte | 1 | 8 | ( − 2 ( 8 − 1 ) -2^{({\color{red}8}-1)} −2(8−1), 2 ( 8 − 1 ) − 1 2^{({\color{red}8}-1)}-1 2(8−1)−1) 即为 (-128 ~ 127) | Byte | 0 |
整型 | short | 2 | 16 | ( − 2 ( 16 − 1 ) -2^{({\color{red}16}-1)} −2(16−1), 2 ( 16 − 1 ) − 1 2^{({\color{red}16}-1)}-1 2(16−1)−1) 即为 (-32,768 ~ 32,767) | Short | 0 |
整型 | int | 4 | 32 | ( − 2 ( 32 − 1 ) -2^{({\color{red}32}-1)} −2(32−1), 2 ( 32 − 1 ) − 1 2^{({\color{red}32}-1)}-1 2(32−1)−1) 即为 (-2,147,483,648 ~ 2,147,483,647) | Integer | 0 |
整型 | long | 8 | 64 | ( − 2 ( 64 − 1 ) -2^{({\color{red}64}-1)} −2(64−1), 2 ( 64 − 1 ) − 1 2^{({\color{red}64}-1)}-1 2(64−1)−1) 即为 (-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807) | Long | 0L |
浮点型 | float | 4 | 32 | (1.4E-45 ~ 3.4028235E38) | Float | 0.0F |
浮点型 | double | 8 | 64 | (4.9E-324 ~ 1.7976931348623157E308) | Double | 0.0D |
布尔型 | boolean | 1 | 8 | true 或 false | Boolean | false |
字符型 | char | 2 | 16 | (0, 2 ( 16 − 1 ) − 1 2^{({\color{red}16}-1)}-1 2(16−1)−1) 单引号括起来的一个字符 | Character | ‘\u0000’ 转为int为0 |
对于以上有以下几点需要注意:
- java八种基本数据类型分为四类八种,四类分别为整型、浮点型、布尔型、字符型;八种分别为byte、short、int、long、float、double、boolean、char;
- java八种基本数据类型的字节数:分别为1、2、4、8个字节;1字节(byte、boolean)、 2字节(short、char)、4字节(int、float)、8字节(long、double);
- 整数的默认类型为int,浮点数的默认类型为double;
- 八种基本数据类型的包装类:除了char的是Character、int类型的是Integer,其他都是首字母大写;
- 关于值的范围问题,需要注意char类型是无符号的,不能为负,所以是0开始的;
基本数据类型的转换
自动转换:低类型的向高类型的转换
如果Java支持将某种类型的数据直接赋值给另一种数据类型的变量,这种方式的类型转换称为自动类型转换或隐式类型转换或扩大转换。
如下图:顺着箭头的方向是可以自动转换的。
注意:在int 转 float、long 转 float或long 转 double时可能会丢失部分精度;在不使用strictfp关键字修饰的float转double时,也可能丢失部分信息。
强制转换:高类型的向底类型转换,但可能会数据溢出或者精度丢失
强制转换在实际中可能出现这三种问题:
1、定义变量时出现的类型转换
public static void main(String[] args) {
//200默认为int类型,这里是自动转换为long类型
long a = 200;
//编译不通过
//2147483648默认应该为int类型,但是超出了int类型的取值范围(int最大值为-2147483648 ~ 2147483647)
long b = 2147483648;
//在整数直接量后面将了一个L,表示该直接量不再默认为int类型,为long类型,所以没错
long c = 2147483648L;
//编译不通过
//浮点数默认为double,double类型大,所以不能直接转换为float
float d = 3.14;
//在浮点数后面加上一个f,表示该直接量不再默认为double,为float类型
float e = 3.14f;
}
以上为几种正常的情况,但是有一种特殊的情况:
int类型直接量可以直接赋给byte、short、char类型变量,只要不超出变量类型的取值范围。
public static void main(String[] args) {
byte a = 100;
short b = 200;
//注意char类型是一种特殊的int类型,可以不用写成单引号括起来的
char c = 100;
//编译不通过
//直接量128超出了byte类型的取值范围
byte d = 128;
//编译不通过
//直接量-1不在char类型的取值范围内
char e = -1;
}
2、数据运算时的类型转换
运算时,运算结果会向较大的类型转换。
public static void main(String[] args) {
int a = 3;
double b = 4;
//输出7.0
System.out.println(a + b);
float c = 3.14f;
//编译不通过
//运算之后变为double类型
c = c + 3.14;
System.out.println(c);
}
特殊情况:
byte、short、char三种数据类型参与运算时,先一律转化为int类型。
public static void main(String[] args) {
byte a = 3;
byte b = 4;
//编译不通过
//此处由于byte类型参与运算时,先直接转换为int类型,但是得出的结果不是int类型
byte c = a + b;
//用int类型接收就行了
int d = a + b;
}
3、强制转换
高等级转为低等级的时候,必须强制转换,但实际工作中不推荐使用强制转换,可能会丢失精度或数据溢出。
public static void main(String[] args) {
int a = 128;
byte b = (byte)a;
//输出-128,出现了数据溢出
System.out.println(b);
double c = 1.23;
int d = (int)c;
//输出1,精度丢失
System.out.println(d);
}
补充说明:
不是只有强制转换的时候会出现数据溢出,例如下面这种情况
public static void main(String[] args) {
int a = 10000000;
int b = 10000000;
int c = a * b;
//输出276447232,得到的结果超出了int类型的范围,数据溢出
System.out.println(c);
}
对应包装类及使用
java是一门面向对象的语言,但是8中基本数据类型不具备面向对象的特征,所以实际使用中很不便,所以为java八种基本数据类型提供了对应的包装类。
基本数据类型 | 对应包装类 | 包装类的父类 |
---|---|---|
byte | java.lang.Byte | java.lang.Number |
short | java.lang.Short | java.lang.Number |
int | java.lang.Integer | java.lang.Number |
long | java.lang.Long | java.lang.Number |
float | java.lang.Float | java.lang.Number |
double | java.lang.Double | java.lang.Number |
boolean | java.lang.Boolean | java.lang.Object |
char | java.lang.Character | java.lang.Object |
- 对应包装类比较特殊的就是int对应的Integer和char对应的Character;
- 对应包装类的直接父类:前6个由于是数,直接父类为Number,而后两个的直接父类就是Object类;
1、常用方法一:静态方法 valueOf()
1、参数为基本数据类型,返回包装类对象;
2、参数为String字符串(Character类没有以String为 参数的该方法),返回包装类对象;
public static void main(String[] args) {
//1.参数为基本数据类型
//作用:将基本数据类型转换为对应包装类
Integer i = Integer.valueOf(10);
//输出10
System.out.println(i);
//2.参数为String字符串时
//作用:返回指定字符串值的包装类对象
Integer a = Integer.valueOf("100");
//输出100
System.out.println(a);
Integer b = Integer.valueOf("100a");
//运行错误,字符串的值不少一个int类型的
System.out.println(b);
}
2、常用方法二:静态方法parseXXX(String str)
1、Character类没有该方法;
2、作用:将字符串装换为对应的基本数据类型(注意此处和上面的valueOf方法返回值的不同);
public static void main(String[] args) {
//作用:将给定字符串装换为对应的基本数据类型
//前提是该字符串必须正确描述该基本数据类型表示的值
int a = Integer.parseInt("100");
//输出100
System.out.println(a);
int b = Integer.parseInt("100a");
//运行错误,字符串的值不为int类型
System.out.println(b);
}
3、常用方法三:非静态方法xxxValue()
1、因为是非静态方法,所以不能像上面两个方法用类名调用了;
2、数字类的包装类(八种包装类中父类是Number的的六个类)才有该方法;
3、作用:将当前包装类对象转换为对应的基本数据类型;
public static void main(String[] args) {
//作用:将包装类对象转换为对应的基本数据类型
//将基本数据类型转换为包装类对象
Integer a = Integer.valueOf(100);
//将包装类对象转换为对应的基本数据类型
int b = a.intValue();
//输出100
System.out.println(b);
Double c = Double.valueOf(2.33);
double d = c.doubleValue();
//输出2.33
System.out.println(d);
}
4、自动拆箱与装箱
1、简介:jdk1.5之后的新特性。该特性是编译器认可的,是在编译器自动将基本数据类型和包装类相互转换,节省了麻烦。
2、自动拆箱 包装类——>基本数据类型 (原理是调用了xxxValue方法)
3、自动装箱 基本数据类型——>包装类 (原理是调用了valueOf方法)
public static void main(String[] args) {
//自动装箱:valueOf
//原理是 Integer i = Integer.valueOf(123);
Integer i = 123;
//自动拆箱
//原理是 int i1 = i.intValue() + 1;
int i1 = i + 1;
//装箱 + 拆箱
//原理为Integer c = Integer.valueOf(a.intValue() + b.intValue());
Integer a = 123;
Integer b = 123;
Integer c = a + b;
}
5、关于valueOf()方法源码研究
以Integer类的valueOf(int i)的源码为例:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
关于源码的理解:Integer类的valueOf(int i)方法首先会判断i是否在-128~127之间,如果在的话,就返回的对象是Integer类中静态数组cache中的对象,如果不是在这之间,就会重新创建一个对象。
通过查看其它类的该方法的源码之后,可以得到该表:
|
|
---|---|
Byte | 直接取,数组范围为(-128,127),且byte值的范围也是(-128,127) |
Short | (-128,127)之间在数组中取,否则new |
Integer | (-128,127)之间在数组中取,否则new |
Long | (-128,127)之间在数组中取,否则new |
Float | 直接new |
Double | 直接new |
Boolean | 直接返回,不new |
Character | 0-127之间从数组中取,否则new |
拓展
1、注意一些容易忽视的类型转换
public static void main(String[] args) {
int a = 10;
double b = 3.4;
//输出:10.0
System.out.println(a > b ? a : b);
//输出:10
System.out.println(a);
}
解析:这里是一个很容易让人不注意的类型转化,这里a与b参与了运算,所以类型向类型大的方向转化,10就变成了10.0,但是a本身是没有变化的
2、+=的情况
Q:以下代码第几行会出错?
public static void main(String[] args) {
short a = 1;
a = a + 1;
a += 1;
}
A:第二行会出错,由于a + 1变为了int类型,而int类型不能直接赋值给short类型;但是 += 这种情况是特殊的,所以不会出错。
3、包装类和基本数据类型比较时,只要值相等就相等
public static void main(String[] args) {
Integer a1 = 127;
Integer a2 = 127;
int a3 = 127;
Integer b1 = 128;
Integer b2 = 128;
int b3 = 128;
//输出:true
System.out.println(a1 == a2);
//输出:true
System.out.println(a1 == a3);
//输出:false
System.out.println(b1 == b2);
//输出:false
System.out.println(b1 == b3);
}
解析:自动装箱时采用valueOf方法,由于127在静态数组的范围内,所以不是new的,而128的两个引用是指向new出现对象的,所以第一个是true,第三个是false。
而包装类和基本数据类型比较时,只要数值是相等的,就相等。
4、char类型存储汉字
Q:char类型能不能存储一个汉字?为什么?
A:能,char类型采用的是Unicode编码,Unicode编码包含汉字,所以char类型自然是可以存储一个汉字的。
5、浮点数精度问题
public static void main(String[] args) {
//输出:false
System.out.println(0.1 * 3 == 0.3);
//输出:0.4
System.out.println(0.1 * 4);
}
解析:有些浮点数不能准确的表示出来,与整数相乘之后出精度丢失,常见为小数位含3的