java开发150个建议( 四 )


看下面这段代码:
1 public class Client6 {2public static void main(String[] args) {3// 向上转型4Base base = new Sub();5base.fun(100, 50);6// 不转型7Sub sub = new Sub();8sub.fun(100, 50);9}10 }11 12 // 基类13 class Base {14void fun(int price, int... discounts) {15System.out.println("Base......fun");16}17 }18 19 // 子类,覆写父类方法20 class Sub extends Base {21@Override22void fun(int price, int[] discounts) {23System.out.println("Sub......fun");24}25 }
该程序中sub.fun(100, 50)报错,提示找不到fun(int,int)方法 。这太奇怪了:子类继承了父类的所有属性和方法,甭管是私有的还是公开的访问权限,同样的参数,同样的方法名,通过父类调用没有任何问题,通过子类调用,却编译不过,为啥?难到是没继承下来?或者子类缩小了父类方法的前置条件?如果是这样,就不应该覆写,@就应该报错呀 。
事实上,base对象是把子类对象做了向上转型,形参列表由父类决定,由于是变长参数,在编译时,base.fun(100, 50);中的50这个实参会被编译器"猜测"而编译成"{50}"数组,再由子类Sub执行 。我们再来看看直接调用子类的情况,这时编译器并不会把"50"座类型转换因为数组本身也是一个对象,编译器还没有聪明到要在两个没有继承关系的类之间转换,要知道JAVA是要求严格的类型匹配的,类型不匹配编译器自然就会拒绝执行,并给予错误提示 。
这是个特例,覆写的方法参数列表竟然与父类不相同,这违背了覆写的定义,并且会引发莫名其妙的错误 。所以读者在对变长参数进行覆写时,如果要使用次类似的方法,请仔细想想是不是要一定如此 。
注意:覆写的方法参数与父类相同,不仅仅是类型、数量,还包括显示形式.
回到顶部
建议7:警惕自增的陷阱
记得大学刚开始学C语言时,老师就说:自增有两种形式,分别是i++和++i,i++表示的先赋值后加1,++i是先加1后赋值,这样理解了很多年也木有问题,直到遇到如下代码,我才怀疑我的理解是不是错了:
1 public class Client7 {2public static void main(String[] args) {3int count=0;4for(int i=0; i<10;i++){5count=count++;6}7System.out.println("count = "+count);8}9 }
这个程序输出的count等于几?是count自加10次吗?答案等于10?可以肯定的说,这个运行结果是count=0 。为什么呢?
count++是一个表达式,是由返回值的,它的返回值就是count自加前的值,Java对自加是这样处理的:首先把count的值(注意是值,不是引用)拷贝到一个临时变量区,然后对count变量+1,最后返回临时变量区的值 。程序第一次循环处理步骤如下:
JVM把count的值(其值是0)拷贝到临时变量区;count的值+1,这时候count的值是1;返回临时变量区的值,注意这个值是0,没修改过;返回值赋给count,此时count的值被重置为0.
"count=count++"这条语句可以按照如下代码理解:
1 public static int mockAdd(int count) {2// 先保存初始值3int temp = count;4// 做自增操作5count = count + 1;6// 返回原始值7return temp;8}
于是第一次循环后count的值为0,其它9次循环也是一样的,最终你会发现count的值始终没有改变,仍然保持着最初的状态.
此例中代码作者的本意是希望count自增,所以想当然的赋值给自身就可以了,不曾想到调到Java自增的陷阱中了,解决办法很简单,把"count=count++"改为"count++"即可 。该问题在不同的语言环境中有着不同的实现:C++中"count=count++"与"count++"是等效的,而在PHP中保持着与JAVA相同的处理方式 。每种语言对自增的实现方式各不相同 。
回到顶部
建议8:不要让旧语法困扰你
1 public class Client8 {2public static void main(String[] args) {3// 数据定义初始化4int fee = 200;5// 其它业务处理6saveDefault: save(fee);7}8 9static void saveDefault() {10System.out.println("saveDefault....");11}12 13static void save(int fee) {14System.out.println("save....");15}16 }