写点什么

每日一道 Java 面试题:方法重载与方法重写,这把指定让你明明白白!

作者:EquatorCoco
  • 2024-01-26
    福建
  • 本文字数:2717 字

    阅读完需:约 9 分钟

写在开头


请聊一聊 Java 中方法的重写和重载?


这个问题应该是各大厂面试时问的最多的话题之一了,它们几乎贯穿了我们日常的开发工作,在过往的博客中我们多多少少都提到过重载重写,而今天我们就一起来详细的学习一下这二者的功能与区别!


重载与重写的定义


重写: 类实现接口或者子类继承父类时,保持方法签名相同,用不同的方法体来实现不同的功能,这也是 Java 三大特性之一多态的具体实现,是垂直方向的“类间行为”。


重载: 在同一个类或者父类与子类之间,保持方法名称相同,参数类型,参数数量,参数顺序不同的一种实现,是水平方向上的“类内行为”,同一个类中,或者父子类中。


方法的重写


如下代码中是一个最简单的重写的实现


public class Dog extends Animal{    public static void main(String[] args) {        Dog dog = new Dog();        dog.method1();    }    @Override    public void method1() {        System.out.println("狗子爱奔跑");    }}class Animal {    public void method1(){        System.out.println("我是动物!");    };}
复制代码


重写的规则


1、重写发生在子类继承父类2、参数列表必须完全与被重写方法的相同3、重写父类方法时,修改方法的权限只能从小范围到大范围4、返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的子类(JDK1.5 及更早版本返回类型要一样,JDK1.7 及更高版本可以不同)5、访问权限不能比父类中被重写的方法的访问权限更低。如:父类的方法被声明为 public,那么子类中重写该方法不能声明为 protected6、重写方法不能抛出新的检查异常和比被重写方法申明更宽泛的异常(即只能抛出父类方法抛出异常的子类)7、声明为 final 的方法不能被重写8、声明为 static 的方法不能被重写9、声明为 private 的方法不能被重写
复制代码


【补充说明】上面的 9 条规则中,前面 6 条应该没什么太多的疑问,访问权限、异常声明范围,子类小于父类,就如同包含与被包含关系,狗子(子类)是动物(父类),那它所拥有的一切自然都要在动物的范畴内!第 7 条,final 关键字修饰的方法,一旦初始化引用不可变,具体可参考之前发的这篇文章面试官:小伙子来说一说Java中final关键字第 8 点,static 修饰的方法不能被重写,这也是一个考点,很好理解,static 修饰的方法属于类方法,在调用的时候直接通过类名.方法名即可,而重写也就是多态是基于对象的,一个静态的方法不会联系到任何实例上,所以也就不存在重写了!但是很多面试官为了考验应聘着的细心,会紧接着问一句,那子类中可以有一个和父类方法签名一致的静态方法吗?


答案是肯定的,如果父类中含有一个静态方法,且在子类中也含有一个返回类型、方法名、参数列表均与之相同的静态方法,那么该子类实际上只是将父类中的该同名方法进行了隐藏,而非重写。 换句话说,父类和子类中含有的其实是两个没有关系的方法,它们的行为也并不具有多态性。


static 关键字内容,可以看这篇文章:深入理解Java中的static关键字


第 9 条就更没什么好说的了,private 表示方法是本类私有,其他类均不可见,更不可能重写了。


方法的重载


重载是发生在编译期间的一种静态绑定,编译器通过方法签名来定位具体重载的哪个方法,如 String 的 valueOf 就是一个方法重载的案例典范,上代码!



目前 String 中 valueOf 重载的方法已多达十几种,用以实现不同的数据类型转换为字符串的逻辑。


是不是觉得重载很简单?不就是方法名相同的情况下,传入不同参数即可调用不同的重载方法,那么我们看看下面的代码



这时若我们分别调用 1、method(),2、method(1),3、method(1L),4、method(null),猜一下答案,嘿嘿



调用 1 时方法 1 和方法 5 均可满足条件(可变参数,参数个数为 0 或多个),但因为 JVM 重载方法时优先通过精准匹配进行选择,所以这里会选择方法 1;调用 2 时,方法 2、3、4、5 均满足,同样因为精准匹配的原因,选择了方法 2;调用 3 时,因为重载方法中没有参数为 long 类型的,所以会通过子类向上转型继承路线依次匹配,最终调用到了方法 4;这里 4 的调用被注释掉了,原因是报错啦,出现了模糊匹配。



参数 null 可以匹配任何一个类对象,这里从满足从子类向上转型进行匹配,但在 Integer 和可变参数的选择上,编译器无法选择,所以编译报错。


由上述的例子其实我们不难看出,在多个重载方法均满足条件时,编译器对于重载的选择是有优先顺序的,下面进行了整理。


编译器选择顺序(从高到底)精准匹配基本数据类型,自动转换为更大范围的基本类型通过装箱与拆箱进行匹配通过子类向上转型继承路线依次匹配通过可变参数匹配
复制代码


重载的规则


1、被重载的方法参数列表(个数或类型)不一样2、被重载的方法可以修改返回类型3、被重载的方法可以修改访问修饰符4、被重载的方法可以修改异常抛出5、方法能够在同一个类中或者在一个子类中被重载6、无法以返回值类型作为重载函数的区分标准
复制代码


【补充说明】


以上 6 点规则中,前 5 点比较好理解,第 6 点也是很多面试官经常会追问的问题,为什么重载的方法,不能将返回值类型作为参考标准。首先,我们看一下这段代码:


public class Dog {    public int method1(int a,int b) {        return a+b;    }    public short method1(int a,int b) {        return (short)(a+b);    }}
复制代码



这段代码中的两个方法,就是保持了返回值类型不同,但提示方法已经被定义,无法重载,说明仅靠返回值类型无法作为方法重载的参考标准!,仔细想想也很容易明白,并不是所有的方法都是有返回值的,难道无返回值的方法重载时,我们还要依赖返回值去判断?​写到这里,俺又想到了一个问题,你们觉得 main()方法可以重载吗


public class OverloadingMain {    public static void main(String[] args) {        System.out.println("String[] args");    }
public static void main(String args) { System.out.println("String args"); }
public static void main() { System.out.println("无参"); }}
复制代码


输出:


String[] args
复制代码


显然,重载是被允许的,但 JVM 在运行时,只会将那个参数为 String[] args 的静态 main 方法作为程序的入口,其他方法只能通过调用去实现打印结果!


重载与重写的区别


基于以上的分析,我们可以精炼出重载与重写的重要区别:


作用范围: 重写的作用范围是父类和子类之间;重载是发生在一个类里面


参数列表: 重载必须不同;重写不能修改


返回类型: 重载可修改;重写方法返回相同类型或子类


抛出异常: 重载可修改;重写可减少或删除,一定不能抛出新的或者更广的异常


访问权限: 重载可修改;重写一定不能做更严格的限制


文章转载自:JavaBuild

原文链接:https://www.cnblogs.com/JavaBuild/p/17988565

体验地址:http://www.jnpfsoft.com/?from=001

用户头像

EquatorCoco

关注

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
每日一道Java面试题:方法重载与方法重写,这把指定让你明明白白!_Java_EquatorCoco_InfoQ写作社区