admin 管理员组文章数量: 1086059
令人发指的关于方法重载和方法重写的一些理解(多态)
令人发指的关于方法重载和方法重写的一些理解
文章目录
- **令人发指的关于方法重载和方法重写的一些理解**
- **方法重载的基础**
- **子类的方法重载**
- **重载升级只重写**
- **顺藤摸瓜之干掉”多态“**
- **总结**
方法重载的基础
很多博客都写着,方法重载有着两同一不同,即“方法名相同,在同一类,参数列表不同”对返回值和访问权限不做限定。这句话有错吗?在不考虑有子类的情况下,这句话总结的可以说是无懈可击。方法名相同这是我们应该公认的。所以重载的时候,编译器通过什么去判断我们写的是重载,没错,就是参数列表,当我们给这些重载的方法,传入不同的参数的时候,编译器就是根据参数类型,数量,来确定你到底调用哪一个方法!相信你肯定会有疑惑,为什么返回值或者说是访问权限修饰符不能作为方法重载的标识。我们一条一条来看:
返回值为什么不能作为方法重载的标识
首先,我们得知道一个知识点:编译时报错优于运⾏时报错。所以当两个⽅法的名字相同,参数个数和类型也相同的时候,虽然返回值类型不同,但依然会提示⽅法已经被定义的错误。⽅法的返回值只是作为⽅法运⾏后的⼀个状态,它是保持⽅法的调⽤者和被调⽤者进⾏通信的⼀个纽带,但并不能作为某个⽅法的‘标识’。
为什么访问权限修饰符不能作为方法重载的标识
有这个想法法很正常,我也曾设想一种场景,就是所有的东西都是一致的,只有我们的权限不同,这样能构成重载吗?可编译器对于方法重载的识别只有参数列表的内容,会依旧报错!我仔细想想,权限修饰符只是改变了方法的可访问区域,就好比一个人在中国是一个人,在世界范围内,他还是中国人,他变了吗?实质是还是一个人,所以这也是不能通过编译的!
还有一个重要的点就是方法重载中的隐式类型转换的问题了,当我们转递的参数,没有找到对应的参数方法时,会发生类型转换,由于可以通过改变参数类型的⽅式实现⽅法重载,那么当传递的参数没有找到匹配的⽅法时,就会发⽣隐式的类型转换。
最后,就是不能写一些让编译器为难的代码,加入两个参数都分别转换一次能有对应的方法,你这让编译器怎么选择了?
子类的方法重载
对于这一点,我当初还是很懵的,不是说方法重载只能发生在父类中吗?为什么会说子类的方法重载,并且我们通过父类这个对象的引用并不能访问到子类重载的父类的方法,为了更好的说明我的逻辑,我写了一个简单的测试。
public class Test2 {public void fun(){System.out.println("我是爸爸1号!");}protected int fun(int a){System.out.println("我是爸爸2号!");return 0;}public static void main(String[] args) {Test2 test2 = new Test2();test2.fun();test2.fun(1);test2.fun(3.0);//本次说明} } class Test3 extends Test2{void fun(double c){System.out.println("我是儿子一号!");} }
我们锁定到这里的 test2.fun(3.0),这里并不能调用儿子类的fun方法。说到这里我们必须得明白虚拟机调用方法的时候存在一个从自身开始向上回溯的过程,如果当前类中有此方法,就用,没有就搜其父类,一直到Object,再搜不到就报NoSuchMethod,所以我们这里得main方法中new得对象是Test2实例化所产生的对象,意味着,我们从这个对象到object类去找我们的方法,找到匹配的参数列表,就会调用该方法!所以开篇说的两同一不同(方法名相同,在同一类,参数列表不同”)中同一个类的含义我们得去理解为我们所实例化的类到object类之间所有可能重载得方法!
那么现在我们想"我是儿子一号!"也与它的父类完成实例化,我们能做什么了?就是去实例化一个Test3的对象!
class Test3 extends Test2{void fun(double c){System.out.println("我是儿子一号!");}public static void main(String[] args) {Test3 test3 = new Test3();float f=3.0f;//隐式类型转换test3.fun(f);test3.fun();test3.fun(1);} }
这个代码就没问题了,我们实例化了一个Test3对象,从这个类的方法开始检索,索然它们都存在与方法区,但是有this和super关键字指向对应的方法,就完成了重载。来看一下输出:
这里发生了隐式类型转换,不清楚的老铁,回退回去看一下。
重载升级只重写
对于一些bug员,比如说我,总在想一些为什么不能有参数列表相同的方法,同一类就不妄想了,编译器也会很”生气“,但是对于父类或者子类的行为,可以我们完全可以想象它们拥有同一种行为(方法名,参数列表相同,这里理解为一种行为的本质),其它的比如返回值,访问权限等,我们需要明白一句话,子类能够代表父类,这句话也是理解多态的关键。回归头来,当重载在这时候迈出一步,方法列表相同,也即是这两个方法已经相同了,因为同名又同参,所以,在一个类里面是不可能出现的,只有子类去覆盖父类的某一个方法。此时子类的方法必须要符合(最起码是兼容)父类中方法的申明,也即,返回值,异常不扩大化,访问控制符不更封闭化。否则,父类里申明了一个方法是公开的,子类给封闭了,根据子类可以当父类看待的原则,这样就是挂羊头卖狗肉了,返回值和异常也类同。
我们还是来看看一个例子:
class Test3 extends Test2{@Overrideprotected int fun(int a) {System.out.println("我是儿子,重写了父类2号!");return 0;}void fun(double c){System.out.println("我是儿子一号!");}public static void main(String[] args) {Test3 test3 = new Test3();float f=3.0f;test3.fun(f);test3.fun();test3.fun(1);}
}
我们重写了父类的 protected int fun(int a)方法,并且new出的是Test3所实例化的对象,所以我们从Test3对象的方法中去向Object寻找我们所调用的方法,因为我们重写了protected int fun(int a)这个方法,在执行test3.fun(1);这个语句的时候,首先在子类中找到了,我们就停止了。如果没找到,会继续向父类中去找,如果子类有一个方法跟父类同名同参,那么搜到子类的该方法就会直接使用,而父类的方法依然存在,只是不会被搜到了,因此也叫覆盖。但我们子类中是有这些父类方法的引用super的,可以直接调用。
来看一下输出:
顺藤摸瓜之干掉”多态“
通过前面的探索我们已经逐渐理解了一下过程,把他们放到一起,你会想到什么?
- 子类可以当父类看待
- 虚拟机调用方法的时候存在一个从自身开始向上回溯的过程,如果当前类中有此方法,就用,没有就搜其父类,一直到Object,再搜不到就报NoSuchMethod。
聪明如你,想到了什么?我再来引导一下,一个类可以与多个子类,也就是说可以将多个子类看成是父类,而我实际new的对象还是子类的对象,只是想这个引用的类型定义为父类(子类可以当父类看待),我们实际去搜索方法,还是从子类去搜索,也即是会率先执行我们所重写的方法,也就是说我们可以无脑将任何子类对象指向父类引用,通过父类引用去调用方法(实际对象是子类,会从子类检索),这也就实现了多态!
理解还是很简单的,了解前面我所说的,相信你对多态有更深的理解。
把前面的代码完善一下,给出一个多态的简单Demo
public class Test2 {public void fun(){System.out.println("我是爸爸1号!");}protected int fun(int a){System.out.println("我是爸爸2号!");return 0;} } class Test3 extends Test2{@Overrideprotected int fun(int a) {System.out.println("我是儿子,重写了父类2号!");return 0;} } class Test4 extends Test2{@Overrideprotected int fun(int a) {System.out.println("我是干儿子,重写了父类2号!");return 0;} } class TestDemo{public static void Demo (Test2 demo){demo.fun(3);//多态}public static void main(String[] args) {Test2 demo1=new Test3();//父类引用指向子类对象Test2 demo2=new Test4();//父类引用指向子类对象Demo(demo1);Demo(demo2);} }
总结
封装,继承,多态,当我们真真静下来去探索其中的奥妙的时候,就会发现一环套一环的感觉,一懂了一个地方,另一个地方有可能就无师自通了,最后由于我的水平有限,很多地方可能表述有限,甚至与官方大佬存在差异,也希望小伙伴有自己的思考,尽管可能是错的,我们便有了一种动力去搞懂他!当我们真正搞懂了的时候,未来提到这个知识点时,那种由内而外散发出来的自信与喜悦是很奇妙的,你就会说一声:”老朋友,好久不见!",好了,夜深了,来日再会!
本文标签: 令人发指的关于方法重载和方法重写的一些理解(多态)
版权声明:本文标题:令人发指的关于方法重载和方法重写的一些理解(多态) 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1688025952a170284.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论