建议6:覆写变长方法也循规蹈矩

在Java中,子类覆写父类中的方法很常见,这样做既可以修正Bug也可以提供扩展的业务功能支持,同时还符合开闭原则(Open-Closed Principle),我们来看一下覆写必须满足的条件:

1.重写方法不能缩小访问权限。

2.参数列表必须与被重写方法相同。

3.返回类型必须与被重写方法的相同或是其子类。

4.重写方法不能抛出新的异常,或者超出父类范围的异常,但是可以抛出更少、更有限的异常,或者不抛出异常。

 public class Client {
public static void main(String[] args) {
//向上转型
Base base = new Sub();
base.fun(100, 50);
//不转型
Sub sub = new Sub();
sub.fun(100, 50);
//编译报错 The method fun(int, int[]) in the type Sub is not applicable for the arguments (int, int)
}
}
//基类
class Base{
void fun(int price,int... discounts){
System.out.println("Base......fun");
}
} //子类,覆写父类方法
class Sub extends Base{
@Override
void fun(int price,int[] discounts){
//Varargs methods should only override or be overridden
//by other varargs methods unlike Sub.fun(int, int[]) and Base.fun(int, int...)
System.out.println("Sub......fun");
}
}

请问:该程序有问题吗?—编译通不过。那问题出在什么地方呢?

@Override注解吗?非也,覆写是正确的,因为父类的calPrice编译成字节码后的 形参是一个int类型的形参加上一个int数组类型的形参,子类的参数列表也与此相同,那覆写是理所当然的了,所以加上@Override注解没有问题, 只是Eclipse会提示这不是一种很好的编码风格。

难道是“sub.fun(100, 50)”这条语句?正解,确实是这条语句报错,提示找不到fun(int,int)方法。这太奇怪了:子类继承了父类的所有属性和方法,甭管是私有的还是 公开的访问权限,同样的参数、同样的方法名,通过父类调用没有任何问题,通过子类调用却编译通不过,为啥?难道是没继承下来?或者子类缩小了父类方法的前 置条件?那如果是这样,就不应该覆写,@Override就应该报错,真是奇妙的事情!

事实上,base对象是把子类对象Sub做了向上转型,形参列表是由父类决定的,由于是变长参 数,在编译时,“base.fun(100, 50)”中的“50”这个实参会被编译器“猜测”而编译成“{50}”数组,再由子类Sub执行。我们再来看看直接调用子类的情况,这时编译器并不会把 “50”做类型转换,因为数组本身也是一个对象,编译器还没有聪明到要在两个没有继承关系的类之间做转换,要知道Java是要求严格的类型匹配的,类型不 匹配编译器自然就会拒绝执行,并给予错误提示。

这是个特例,覆写的方法参数列表竟然与父类不相同,这违背了覆写的定义,并且会引发莫名其妙的错误。所以读者在对变长参数进行覆写时,如果要使用此类似的方法,请找个小黑屋仔细想想是不是一定要如此。

注意 覆写的方法参数与父类相同,不仅仅是类型、数量,还包括显示形式。

[改善Java代码]覆写变长方法也循规蹈矩的更多相关文章

  1. [改善Java代码]覆写equals方法必须覆写hashCode方法

    覆写equals方法必须覆写hashCode方法,这条规则基本上每个Javaer都知道,这也是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先 ...

  2. [改善Java代码]覆写equals方法时不要识别不出自己

    建议45: 覆写equals方法时不要识别不出自己 我们在写一个JavaBean时,经常会覆写equals方法,其目的是根据业务规则判断两个对象是否相等,比如我们写一个Person类,然后根据姓名判断 ...

  3. [改善Java代码]避免带有变长参数的方法重载

    建议4: 避免带有变长参数的方法重载 在项目和系统的开发中,为了提高方法的灵活度和可复用性,我们经常要传递不确定数量的参数到方法中,在Java 5之前常用的设计技巧就是把形参定义成Collection ...

  4. [改善Java代码]用枚举实现工厂方法模式更简洁

    工厂方法模式(Factory Method Patter)是"创建对象的接口",让子类决定实例化哪一个类,并使一个类的实例化延迟到其子类.工厂方法模式在我们的开发工作中,经常会用到 ...

  5. [改善Java代码]自由选择字符串拼接方法

    对一个字符串拼接有三种方法:加号,contact方法,StringBuffer或者StringBuilder的append方法,其中加号是最常用的.其他两种方式偶尔会出现在一些开源项目中,那么这三者有 ...

  6. [改善Java代码]别让null值和空值威胁到变长方法

    建议5:别让null值和空值威胁到变长方法 public class Client { public void methodA(String str,Integer... is){ } public ...

  7. [改善Java代码]警惕泛型是不能协变和逆变的

    什么叫做协变(covariance)和逆变(contravariance)? 在变成语言的类型框架中,协变和逆变是指宽类型和窄类型在某种情况下(如参数,泛型,返回值)替换或交换的特性,简单的说,协变是 ...

  8. [改善Java代码]让多重继承成为现实

    建议41: 让多重继承成为现实 在Java中一个类可以多重实现,但不能多重继承,也就是说一个类能够同时实现多个接口,但不能同时继承多个类.但有时候我们确实需要继承多个类,比如希望拥有两个类的行为功能, ...

  9. 使用第三方工具覆写Object中方法

    我们在实际开发中,经常需要覆写Object中的equals,hashcode,toString方法,其实编写这些代码并不是很难,但很枯燥和乏味. 下面推荐Google的Guava jar包来覆写上面的 ...

随机推荐

  1. HDU 5724 Chess (sg函数)

    Chess 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5724 Description Alice and Bob are playing a s ...

  2. Spring EL hello world example

    The Spring EL is similar with OGNL and JSF EL, and evaluated or executed during the bean creation ti ...

  3. jeecms附件标签用法

    [#if content.attachments?size gt 0] [#list content.attachments as attach] <a id="attach${att ...

  4. myeclipse内存配置

    配置文件路径:D:\work\myeclipse\MyEclipse for Spring 10\myeclipseforspring.ini 替换以下内容即可 -vmargs-Xmx768m-XX: ...

  5. windows 花式装系统

    目录 一.安装系统前准备 准备U盘 准备好一个制作启动盘的软件 准备系统镜像 二.接下来先制作启动盘(以微PE为例) 三.插上u盘,调BIOS(BIOS即基本输入输出系统) 四.进入PE 五.开始安装 ...

  6. js两种创建对象方式

    js创建方法的两种方式 <%@ page language="java" contentType="text/html; charset=ISO-8859-1&qu ...

  7. Java学习笔记(八):集合类

    Java中对数据的存储会使用到集合类,下面我们来看看Java中常用的集合类. Collection接口 集合的接口,可以简单的理解为可以动态扩充的数组. Collection接口定义了很多相关的方法, ...

  8. JavaScript- 获取经度纬度

    昨天获得一个小需求,需要取地理位置. 通过以下的JS能获得经度和纬 if(navigator.geolocation) { navigator.geolocation.getCurrentPositi ...

  9. ASP导出Word带页眉页脚,中文不乱码

    关键代码: <% Response.Clear() Response.CodePage= Response.Charset="UTF-8" Response.ContentT ...

  10. Qt + CURL + mimetic 发送邮件(带附件)

    使用了大名鼎鼎的CURL 开源库,以及mimetic开源库. CURL支持N多协议.功能超强,但是不能直接发邮件附件,需要自己拼mime.太麻烦,于是乎~~ mimetic主要用于构造邮件mimeti ...