每日一道 Java 面试题:方法重载与方法重写,这把指定让你明明白白!
写在开头
请聊一聊 Java 中方法的重写和重载?
这个问题应该是各大厂面试时问的最多的话题之一了,它们几乎贯穿了我们日常的开发工作,在过往的博客中我们多多少少都提到过重载与重写,而今天我们就一起来详细的学习一下这二者的功能与区别!
重载与重写的定义
重写: 类实现接口或者子类继承父类时,保持方法签名相同,用不同的方法体来实现不同的功能,这也是 Java 三大特性之一多态的具体实现,是垂直方向的“类间行为”。
重载: 在同一个类或者父类与子类之间,保持方法名称相同,参数类型,参数数量,参数顺序不同的一种实现,是水平方向上的“类内行为”,同一个类中,或者父子类中。
方法的重写
如下代码中是一个最简单的重写的实现
重写的规则
【补充说明】上面的 9 条规则中,前面 6 条应该没什么太多的疑问,访问权限、异常声明范围,子类小于父类,就如同包含与被包含关系,狗子(子类)是动物(父类),那它所拥有的一切自然都要在动物的范畴内!第 7 条,final 关键字修饰的方法,一旦初始化引用不可变,具体可参考之前发的这篇文章面试官:小伙子来说一说Java中final关键字第 8 点,static 修饰的方法不能被重写,这也是一个考点,很好理解,static 修饰的方法属于类方法,在调用的时候直接通过类名.方法名即可,而重写也就是多态是基于对象的,一个静态的方法不会联系到任何实例上,所以也就不存在重写了!但是很多面试官为了考验应聘着的细心,会紧接着问一句,那子类中可以有一个和父类方法签名一致的静态方法吗?
答案是肯定的,如果父类中含有一个静态方法,且在子类中也含有一个返回类型、方法名、参数列表均与之相同的静态方法,那么该子类实际上只是将父类中的该同名方法进行了隐藏,而非重写。 换句话说,父类和子类中含有的其实是两个没有关系的方法,它们的行为也并不具有多态性。
static 关键字内容,可以看这篇文章:深入理解Java中的static关键字
第 9 条就更没什么好说的了,private 表示方法是本类私有,其他类均不可见,更不可能重写了。
方法的重载
重载是发生在编译期间的一种静态绑定,编译器通过方法签名来定位具体重载的哪个方法,如 String 的 valueOf 就是一个方法重载的案例典范,上代码!
![](https://static001.geekbang.org/infoq/e1/e1176d8c89502a23a72076197e90661b.png)
目前 String 中 valueOf 重载的方法已多达十几种,用以实现不同的数据类型转换为字符串的逻辑。
是不是觉得重载很简单?不就是方法名相同的情况下,传入不同参数即可调用不同的重载方法,那么我们看看下面的代码
![](https://static001.geekbang.org/infoq/81/81a0916e8dec36294681646ff9402bee.png)
这时若我们分别调用 1、method(),2、method(1),3、method(1L),4、method(null),猜一下答案,嘿嘿
![](https://static001.geekbang.org/infoq/8d/8d54c89a258d3363c6fd552318a550d3.png)
调用 1 时方法 1 和方法 5 均可满足条件(可变参数,参数个数为 0 或多个),但因为 JVM 重载方法时优先通过精准匹配进行选择,所以这里会选择方法 1;调用 2 时,方法 2、3、4、5 均满足,同样因为精准匹配的原因,选择了方法 2;调用 3 时,因为重载方法中没有参数为 long 类型的,所以会通过子类向上转型继承路线依次匹配,最终调用到了方法 4;这里 4 的调用被注释掉了,原因是报错啦,出现了模糊匹配。
![](https://static001.geekbang.org/infoq/8e/8e046842940429bc04631dfcf26e5ce6.png)
参数 null 可以匹配任何一个类对象,这里从满足从子类向上转型进行匹配,但在 Integer 和可变参数的选择上,编译器无法选择,所以编译报错。
由上述的例子其实我们不难看出,在多个重载方法均满足条件时,编译器对于重载的选择是有优先顺序的,下面进行了整理。
重载的规则
【补充说明】
以上 6 点规则中,前 5 点比较好理解,第 6 点也是很多面试官经常会追问的问题,为什么重载的方法,不能将返回值类型作为参考标准。首先,我们看一下这段代码:
![](https://static001.geekbang.org/infoq/64/64337ab72cc739030909e402dd124493.png)
这段代码中的两个方法,就是保持了返回值类型不同,但提示方法已经被定义,无法重载,说明仅靠返回值类型无法作为方法重载的参考标准!,仔细想想也很容易明白,并不是所有的方法都是有返回值的,难道无返回值的方法重载时,我们还要依赖返回值去判断?写到这里,俺又想到了一个问题,你们觉得 main()方法可以重载吗?
输出:
显然,重载是被允许的,但 JVM 在运行时,只会将那个参数为 String[] args 的静态 main 方法作为程序的入口,其他方法只能通过调用去实现打印结果!
重载与重写的区别
基于以上的分析,我们可以精炼出重载与重写的重要区别:
作用范围: 重写的作用范围是父类和子类之间;重载是发生在一个类里面
参数列表: 重载必须不同;重写不能修改
返回类型: 重载可修改;重写方法返回相同类型或子类
抛出异常: 重载可修改;重写可减少或删除,一定不能抛出新的或者更广的异常
访问权限: 重载可修改;重写一定不能做更严格的限制
文章转载自:JavaBuild
评论