建议23 不要让类型默默转换
基本类型转换时,使用主动声明方式(注意不是强制类型转换),例如:
final int SPEED = 30 * 1000 * 1000
long num2 = 1L * SPEED * 60 *800
建议24 边界
如果一个方法接受的是int类型参数,那正最大和负最小的边界值是必测的!
建议26 提防包装类型的null值
包装类型参与运算时,要做null值校验。
错误代码如下:
public static int func(List<Integer> list){
int count = 0;
for(int i : list){
count += i;
}
return count;
}
当list.add(null)时,运行结果为空指针异常:
原因是:包装类型(Integer等)的存在是为了解决基本类型实例化的问题,如想把一个整型放到List中,就必须使用Integer包装类型。而基本类型和包装类型是可以通过自动装箱和自动拆箱自由转换的。在for循环中,隐含了Integer->Int拆箱过程,拆箱过程是通过调用包装对象的intValue方法来实现,由于包装对象是null,访问intValue方法时会报空指针异常。
正确代码如下:
public static int func(List<Integer> list){
int count = 0;
for(Integer i : list){
count += (i != null) ? i : 0;
}
return count;
}
建议27 谨慎使用包装类型的大小比较
只要是两个对象之间的比较(包装类型也是对象),就应该采用相应的方法,如Integer实例的compareTo方法,而不是通过Java默认的机制(==, <, >)来处理。
在判断对象是否相等时,最好使用equals方法,避免使用“==”。
(1)i > j 和 i < j
在Java 中,“>”和“<”用来判断两个数字类型的大小关系,注意只能是数字型的判断,对于Integer 包装类型,是根据其intValue() 方法的返回值(也就是其相应的基本类型)进行比较的(其他包装类型是根据相应的value 值来比较的,如doubleValue、floatValue 等),那很显然,两者不可能有大小关系的。
(2)i == j
Java中“==”判断对象如果是基本类型则判断值是否相等,若是对象,则判断是否是一个对象的两个引用,即地址是否相等。
建议28 优先使用整形池
声明包装类型的时候,使用valueOf()生成,而不是通过构造函数生成。这样使用整型池,不仅仅提高了系统性能,同时节约了内存空间。
包装类型产生对象的两种方式:
(1)new产生的Integer对象
(2)装箱生成的对象
装箱动作是通过valueOf()方法实现的,我们阅读以下Integer.valueOf的实现代码:
public static Integer valueOf(int i){
final int offset = 128;
if(i >= -128 && i <= 127){
return IntegerCache.cache(i + offset);
}
retrun new Integer(i);
}
这段代码,如果是-128至127之间的int类型转换为Integer对象,则直接从cache数组中获得,代码如下:
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static{
for(int i = 0; i < cache.length; i++){
cache[i] = new Integer(i-128);
}
}
cache是IntegerCache内部类的一个静态数组,容纳的是-128到127之间的Integer对象,通过valueOf产生包装对象时,如果int参数在-128和127之间,则直接从整形池中获得对象,不在该范围的int类型则通过new生成包装对象。