对于大多数编程语言,把一种类型的值赋给另外类型的变量是很常见的操作。Java是强类型语言,不是所有的类型都可以随便自动转换。
把 int 类型的值赋给 long 类型的变量,总是可行的。但是,反过来,将 long 类型 赋值给 int 类型,你必须使用强制类型转换。
Java 的类型转换分两种:
- 自动类型转换 – 没有任何的表现形式,Java自动处理
- 强制类型转换 – 需要使用类型转换语法
Java的自动转换
Java的自动转换,需要满足下面的两个条件:
- 这2种类型是兼容的
- 目的类型数的范围比来源类型的大
在 Java 中8种基本数据类型 中,对基本数据类型分了组。
数字类型,包括整数integer
和浮点floating-point
类型都是彼此兼容的,但是,数字类型和字符类型char
或布尔类型bollean
是不兼容的。字符类型char
和布尔类型bollean
也是互相不兼容的。
public static void main(String[] args) {
int w = 3;
long width;
width = w;
System.out.println("int " + w + " long " + width );
}
类型的强制转换
有时候,你需要将 int 型的值赋给一个 byte 型的变量,你将怎么办?这种转换不会自动进行,因为 byte 型的变化范围比 int 型的要小。取值范围可以参考Java 中8种基本数据类型
强制类型转换只不过是一种显式的类型变换。它的通用格式如下:
(target_type)value;
其中,目标类型(target-type)指定了要将指定值转换成的类型。
public static void main(String[] args) {
long height = 34L;
int h;
h = (int) height;
System.out.println("int " + h + " long " + height );
}
将 long 赋值给 int,并不能自动发生,需要 (int) height
将至转换。
下面有两段程序,注意观察它们的区别:
public static void main(String[] args) {
int key = 29;
byte bit = (byte)key;
System.out.println("int " + key + " byte " + bit);
}
public static void main(String[] args) {
int key = 285;
byte bit = (byte)key;
System.out.println("int " + key + " byte " + bit);
}
查看结果,简直是个神奇的现象,不同的 int 值,竟然转换以后,能得到相同的 byte 值。
在将 int 型强制转换成 byte 型时,如果整数的值超出了 byte 型的取值范围–128~127
,它的值将会因为对 byte 型值域取模(整数除以byte得到的余数)而减少。
将 285 转换为 byte 时,其结果是 285 除以 256 的余数 29,这里 256 是byte类型的变化范围,从 –128~127 一共 256 个变化。
当把浮点值赋给整数类型时一种不同的类型转换发生了:截断truncation
。整数没有小数部分,所以,当把浮点值赋给整数类型时,它的小数部分会被舍去。
public static void main(String[] args) {
double money = 3.5d;
int m = (int) money;
System.out.println("double " + money + " int "+m);
}
将浮点数值 3.5 赋给一个整数,其结果值只是3,0.5被丢弃了。当然,如果浮点值太大而不能适合目标整数类型,那么它的值将会因为对目标类型值域取模而减少。
public static void main(String[] args) {
boolean flag = true;
int value = (int)flag;
}
上面的代码是不正确的,强制类型转换并不能在不兼容的数据类型之间发生。
如果强制转换,将会出现错误:
java.lang.ClassCastException
类型提升
类型转换发生在简单赋值(=)阶段,如果是表达式赋值,还有另外一种类型转换。
public static void main(String[] args) {
byte b = 3;
char c = 'a';
int d = b*c;
System.out.println("d is " + d);
}
中间项结果 b*c
很容易超过它的任何一个 byte 型操作数的范围。为处理这种问题,当计算表达式时,Java 自动提升 各个byte型或short型的操作数到int型。这意味着子表达式b*c
使用整数而不是字节型或字符来执行。虽然结果已经超出了 byte 类型的取值范围,但是结果是正确的。
对于 char 类型的 ‘a’ ,对应的ACCSII 码值为 97,所以表达式的值为 3×97。
public static void main(String[] args) {
byte b = 6;
byte c = 8;
byte d = b + c ;
}
上面的代码想要计算两个 byte 值之间的和,但是代码不能通过编译。因为Java自动提升了类型。
表达式 b + c
求值的时候,操作数被自动地提升为int型,计算结果也被提升为int型。这样,表达式的结果现在是int型,不强制转换它就不能被赋为byte型。
public static void main(String[] args) {
byte b = 6;
byte c = 8;
byte d = (byte) (b + c);
System.out.println(d);
}
使用强制类型转换,代码正常编译,结果正确。
类型提升的约定
Java定义了若干适用于表达式的类型提升规则:
- 所有的byte型和short型的值被提升到 int型
- 如果一个操作数是long型,整个表达式将被提升到long型
- 如果一个操作数是float型,整个表达式将被提升到float型
- 如果一个操作数是double型,计算结果就是double型
public static void main(String[] args) {
byte b = 2;
char c = 'c';
short s = 3;
int i = 50000;
float f = 8.23f;
double d = 33.14;
double result = (f * b) + (i / c) - (d * s);
System.out.println((f * b) + " + " + (i / c) + " - " + (d * s));
System.out.println(result);
}
422.04002197265623
这个例子有点复杂:
第一个子表达式 f*b
中,变量b被提升为float类型,该子表达式的结果当然是float类型。
第二个子表达式 i/c
中,变量c被提升为int类型,该子表达式的结果当然是int类型。
第三个子表达式 d*s
中,变量s被提升为double类型,该子表达式的结果当然也是double类型。
最后,考虑三个中间值,float类型,int类型,和double类型。float类型加int类型的结果是float类型。然后float类型减去提升为double类型的double类型,该表达式的最后结果是double类型。