文章目录
前言
Java中的基本数据类型(Primitive Data Types)共有8种,它们是Java最基本的单元,我们的每一段程序中都有它们的身影。
本文将探讨这些基本数据类型的部分使用技巧。
一、用偶判断,不用奇判断
偶数是能够被2所整除的整数。正偶数也称双数。若某数是2的倍数,它就是偶数,可表示为2n;若非,它就是奇数,可表示为2n+1(n为整数),即奇数除以二的余数是1。
知道了奇偶数的定义,让我们来看一下这段代码:
public class Test {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
Collections.addAll(numbers,2,1,0,-1);
for (Integer number : numbers) {
String str = number + "是一个:" + (number%2==1?"奇数":"偶数");
System.out.println(str);
}
}
}
这是一段完全符合奇偶数定义的代码,那么他的执行结果如何呢?
2是一个:偶数
1是一个:奇数
0是一个:偶数
-1是一个:偶数
完美按照定义执行写的代码,-1却被判定为了偶数,这是为什么呢?那就让我们先了解一下Java中的取余算法吧。
/**
* 模拟取余计算
* @param dividend 被除数
* @param divisor 除数
* @return 余数
*/
public static int remainder(int dividend,int divisor){
return dividend - dividend/divisor * divisor;
}
根据上面的模拟取余可知,当我们输入-1的时候,运算结果是-1。因为不等于1,所以被判定为了偶数。解决起来也很简单用偶判断,不用奇判断即可。
public class Test {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
Collections.addAll(numbers,2,1,0,-1);
for (Integer number : numbers) {
String str = number + "是一个:" + (number%2==0?"偶数":"奇数");
System.out.println(str);
}
}
}
二、要小心边界值及自动转换
做一道简单的乘法运算题
public class Test {
//光速是30万公里每秒
public static final int LIGHT_SPEED = 30 * 10000 * 1000;
public static void main(String[] args) {
System.out.println("题目:太阳光照到地球需要8分钟,计算太阳到地球的距离");
//要超出int类型范围,使用long类型接收
long dis = LIGHT_SPEED * 60 * 8 ;
System.out.println("太阳与地球的举例是" + dis + "米");
}
}
题目:太阳光照到地球需要8分钟,计算太阳到地球的距离
太阳与地球的举例是-2028888064米
奇怪,不是已经考虑到int类型可能越界采用long类型了吗,为什么还会出现负值呢?
那是因为Java是先运算然后再进行类型转换的,dis的三个运算参数都是int类型,三者相乘的结果也是int类型,但因为超过了int的最大值,所以其值变为负值,再转换为long类型依然是负值。
解决起来也很简单,主动声明类型转换即可。
public class Test {
//光速是30万公里每秒
public static final int LIGHT_SPEED = 30 * 10000 * 1000;
public static void main(String[] args) {
System.out.println("题目:太阳光照到地球需要8分钟,计算太阳到地球的距离");
//要超出int类型范围,使用long类型接收
long dis = 1L * LIGHT_SPEED * 60 * 8 ;
System.out.println("太阳与地球的举例是" + dis + "米");
}
}
三、优先使用基本数据类型
因为包装类有很多便利的功能和特殊的使用场景,如集合中,和String类型的转换等。且包装类和基本数据类型可以自动转换,这使得包装类在开发中已经随处可见。但无论从安全性、性能及稳定性来说,基本数据类型都是首选方案。
我们来看一段代码:
public class Test {
public static void main(String[] args) {
Test test = new Test();
int i = 100;
test.f(i);
test.f(Integer.valueOf(i));
}
public void f(long l){
System.out.println("基本类型的方法被调用");
}
public void f(Long l){
System.out.println("包装类型的方法被调用");
}
}
思考该程序是否能编译,如果能编译输出结果又是什么呢?
先说结论,首先这段代码是能够编译的,执行结果如下:
基本类型的方法被调用
基本类型的方法被调用
自动装箱有一个重要的原则:基本类型可以先加宽,再转变成宽类型的包装类型,但不能直接转变成宽类型的包装类型。
例:
public class Test {
public static void main(String[] args) {
Test test = new Test();
int i = 100;
test.f(i);
}
public void f(Long l){
System.out.println("包装类型的方法被调用");
}
}
这段代码是编译通不过的,因为i是一个int类型,不能自动转变为Long类型。但是修改成以下代码就可以编译通过了。
public class Test {
public static void main(String[] args) {
Test test = new Test();
int i = 100;
long l = i;
test.f(l);
}
public void f(Long l){
System.out.println("包装类型的方法被调用");
}
}
这就是int类型先加宽为long型,然后再自动转换为Long型。
test.f(Integer.valueOf(i))是如何调用的呢?nteger.valueOf(i)返回的是一个Integer对象,没有f(Integer i)方法,编译器会尝试转换成int类型的实参调用,与f(i)相同,int类型被加宽成了long类型成功调用了基本类型的方法。
使用包装类型确实有方便的地方,但是也会引起一些不必要的困惑,比如我们这个例子,如果方法重载使用的是基本类型,实参也是基本类型,就不会产生以上问题,而且程序的可读性更强。自动装/拆箱虽然方便,但引起的问题也非常严重——我们甚至不知道执行的是哪个方法。
总结
本文主要总结了几条基本数据类型的使用技巧。
1.用偶判断,不用奇判断。
2.要小心边界值及自动转换。
3.优先使用基本数据类型。
参考文献
[1]秦小波.编写高质量代码[M]:机械工业出版社