类型转换操作符
类型转换(cast) 的原意是“模型铸造”。在适当的时候,Java会将一种数据类型自动转换成另一种。
例如,假设我们为某浮点变量赋以一个整数值,编译器会将int自动转换成float。
类型转换运算允许我们显式地进行这种类型的转换,或者在不能自动进行转换的时候强制进行类型转换。
要想执行类型转换,需要将希望得到的数据类型置于圆括号内,放在要进行类型转换的值得左边,可以在下面的示例中看到它:
//: operators/Casting.java
public class Casting {
public static void main(String[] args) {
int i = 200;
long lng = (long)i;
lng = i; // "Widening," so cast not really required
long lng2 = (long)200;
lng2 = 200;
// A "narrowing conversion":
i = (int)lng2; // Cast required
}
} ///:~
正如所看到的,既可以对数值进行类型转换,亦可对变量进行类型转换。
请注意,这里可能会引入”多余的“转型,例如,编译器在必要的时候回自动进行int值到long值得提升。
但是你仍然可以做这样”多余的“事,以提醒自己需要留意,也可以使代码更清楚。
在其他情况下,可能只有先进行类型转换,代码编译才能通过。
在C和C++中,类型转换有时会让人头痛。
但是在Java中,类型转换则是一种比较安全的操作。
然而,如果要执行一种名为窄化转化(narrowing conversion)的操作(也就是说,将能容纳更多信息的数据类型转换成无法容纳那么多信息的类型),就有可能面临信息丢失的危险。
此时,编译器会强制我们进行类型转换,这实际上是说:“这可能是一件危险的事情,如果无论如何要这么做,必须显式地进行类型转换”。
而对于扩展转换(widening conversion),则不必显式地进行类型转换,因为新类型肯定能容纳原来类型的信息,不会造成任何信息的丢失。
Java允许我们把任何基本数据类型转换成别的基本数据类型,但布尔型除外,后者根本不允许进行任何类型的转换处理。
“类”数据类型不允许进行类型转换。
为了将一种类转换成另一种,必须采用特殊的方法(本书后面会讲到,对象可以在其所属类型的类族之间可以进行类型转换;
例如,“橡树”可转型为“树”;反之亦然。但不能把它转换成类族以外的类型,如“岩石”)。
Truncation and rounding
截尾和舍入
在执行窄化转换时,必须注意截尾与舍入问题。
例如,如果价格一个浮点值转换为整型值,Java会如何处理呢?
例如将29.7转换为int,结果是30还是29?在下面的示例中可以找到答案:
//: operators/CastingNumbers.java
// What happens when you cast a float
// or double to an integral value?
import static net.mindview.util.Print.*;
public class CastingNumbers {
public static void main(String[] args) {
double above = 0.7, below = 0.4;
float fabove = 0.7f, fbelow = 0.4f;
print("(int)above: " + (int)above);
print("(int)below: " + (int)below);
print("(int)fabove: " + (int)fabove);
print("(int)fbelow: " + (int)fbelow);
}
} /* Output:
(int)above: 0
(int)below: 0
(int)fabove: 0
(int)fbelow: 0
*///:~
因此答案是在将float或double转型为整型值时,总是对该数字执行截尾。
如果想要得到舍入的结果,就需要使用java.lang.Math中的round()方法:
//: operators/RoundingNumbers.java
// Rounding floats and doubles.
import static net.mindview.util.Print.*;
public class RoundingNumbers {
public static void main(String[] args) {
double above = 0.7, below = 0.4;
float fabove = 0.7f, fbelow = 0.4f;
print("Math.round(above): " + Math.round(above));
print("Math.round(below): " + Math.round(below));
print("Math.round(fabove): " + Math.round(fabove));
print("Math.round(fbelow): " + Math.round(fbelow));
}
} /* Output:
Math.round(above): 1
Math.round(below): 0
Math.round(fabove): 1
Math.round(fbelow): 0
*///:~
由于round()是java.lang的一部分,因此在使用它时不需要额外地导入。
Promotion
提升
如果对基本数据类型执行算数运算或按位运算,大家会发现,只要类型比int小(即char/byte或者short),
那么在运算之前,这些值会自动转换成int。
这样一来,最终生成的结果就是int类型。如果想把结果赋值给较小的类型,就必须使用类型转换
(既然把结果赋给了较小的类型,就可能出现信息丢失)。
通常,表达式中出现的最大的数据类型决定了表达式最终结果的数据类型。
如果将一个float值与一个double值想乘,结果就是double;
如果将一个int和一个long值相加,则结果为long。