参考资料:彻底理解Java中的基本数据类型转换(自动、强制、提升)
神奇的溢出
没有强制转换引起的溢出
- 题目367:
有效的完全平方数
- 思路:
本题我选择做进阶版,即不使用任何内置函数,所以我选择使用二分法来解决本题。那么问题来了,当我写好了我的代码提交时,发生了以下现象:
可以看到我在没改我的原始代码时,是会超出时间限制的,俗称溢出。那么此时我的代码是如下:
class Solution {
public boolean isPerfectSquare(int num) {
int left = 0, right = num;
while (left <= right) {
int mid = (right - left) / 2 + left;
long square = mid * mid;
if (square < num) {
left = mid + 1;
} else if (square > num) {
right = mid - 1;
} else {
return true;
}
}
return false;
}
}
遇到溢出最应该想到的是会不会出现死循环,但很可惜,答案是否定的,遍历已经涵盖了所有情况且不会出现死循环,那么究竟是哪里出了问题呢?还是说O(logn)的时间复杂度不足以跑完本题的全部示例?
- 改进的代码(提交通过):
class Solution {
public boolean isPerfectSquare(int num) {
int left = 0, right = num;
while (left <= right) {
int mid = (right - left) / 2 + left;
long square = (long) mid * mid;
if (square < num) {
left = mid + 1;
} else if (square > num) {
right = mid - 1;
} else {
return true;
}
}
return false;
}
}
嗯??是不是和上面溢出的代码很像?其实不同就只有一处,那就是在计算long square = mid * mid这一步时,我在代码里就进行了强制类型转换,而不是等着java自动cast数据类型。
- 原因:
没有进行强制数据转换
但是理解到这一步,显然说服不了任何人,所以我们如果想彻底了解这一问题的原因,就要先了解java中数据类型转换的原理和机制。
- java中的数据类型转换:
java的数据类型转换包括:自动转换、强制转换和提升转换。
1. java中的8种基本数据类型:
2. 自动类型转换
自动类型转换是指:数字表示范围小的数据类型可以自动转换成范围大的数据类型。很显然本题中,最开始我们使用的就是自动类型转换,很可惜溢出了。具体自动转换如下图所示:
其中实线表示数据不会丢失,而虚线可能会出现数据丢失的问题。
自动类型转换要小心数据溢出问题
int count = 100000000;
int price = 1999;
long totalPrice = count * price;
编译没任何问题,但结果却输出的是负数,这是因为两个 int 相乘得到的结果是 int, 相乘的结果超出了 int 的代表范围。
这种情况,一般把第一个数据转换成范围大的数据类型再和其他的数据进行运算。
int count = 100000000;
int price = 1999;
long totalPrice = (long) count * price;
那么破案了!我们做这道题会溢出的最根本的原因早到了,即我们算出来的square变成了负数,这个时候和num比较大小的话是肯定比num小的,计算量加大导致了溢出。
另外,向下转换时可以直接将 int 常量字面量赋值给 byte、short、char 等数据类型,而不需要强制转换,只要该常量值不超过该类型的表示范围都能自动转换。
3. 强制类型转换
即强制显示的把一个数据类型转换为另外一种数据类型。
先来看能够正常强制转换的例子:
short s = 199;
int i = s;// 199
double d = 10.24;
long ll = (long) d;// 10
数据溢出问题:
int ii = 300;
byte b = (byte)ii;
300 已经超出了 byte 类型表示的范围,所以会转换成一个毫无意义的数字。
4. 类型提升
所谓类型提升就是指在多种不同数据类型的表达式中,类型会自动向范围表示大的值的数据类型提升。
long count = 100000000;
int price = 1999;
long totalPrice = price * count;
price 为 int 型,count 为 long 型,运算结果为 long 型,运算结果正常,没有出现溢出的情况。