java基础--覆盖与重载
导语
昨天看spring源码时发现重载和覆盖用的很多,又想起之前面试实习居然混淆了,平时不爱看书,又不总结,对于基础知识感觉懂又不全懂。
直接看代码
一个简单的例子:
public interface Animal { default Animal getInstance() {return this;} default void perform(){System.out.println("default perform...");} } public class Dog implements Animal { @Override public void perform() {System.out.println("dog is in the performance...");} } public class Cat implements Animal { @Override public Cat getInstance() {return this;} } public class Main { public static void main(String[] args) { Animal animal = new Dog(); animal.perform(); } }
这个例子很简单,但还是要拿出来,主要是Cat复写getInstance时,改变了其返回值,依旧是覆盖。但是如果改成不是原返回值类型的子类时则会报错,不是重载也不是继承,直接是函数重名错误。那么就可以推广到,一个类无法实现了有方法重名且返回值没有继承关系的两个接口。
复杂点的例子:
public abstract class AbstractAnimal implements Animal{ @Override """ 记住,我们是商人. """ public abstract Animal getInstance() throws Exception; @Override public final void perform (){ try { this.getInstance().perform(); } catch (Exception e) { System.out.println("Animals are missing..."); } } protect abstract buyAnimals(); } public class Zookeeper extends AbstractAnimal { public static int times = 0; List<Animal> animals; public Zookeeper() { this.buyAnimals(); } @Override public Animal getInstance() throws Exception { if(animals== null || animals.size()==0) throw new Exception("Zookeeper has no animals..."); times++; return animals.get(times % animals.size()); } public final void perform(int index) { if(animals.size() <= index) super.perform(); else this.animals.get(index).perform(); } public void perform(Class type) { for(Animal a: animals) { if(a.getClass() == type) { a.perform(); return; } } System.out.println("no such animals: " + type.getClass().getSimpleName()) ; } /** public Animal perform(int index) { if(animals.size() <= index) index = animals.size(); Animal animal = animals.get(index); animal.perform(); return animal; } */ @Override public void buyAnimals() { if(animals == null) animals = new ArrayList<>(); this.animals.add(new Cat()); this.animals.add(new Dog()); this.animals.add(new Cat()); } } public class Main { public static void main(String[] args) { Animal zookeeper = new Zookeeper(); zookeeper.perform(); // zookeeper.perform(3); 无法使用 zookeeper.perform(); Zookeeper zookeeper1 = new Zookeeper(); zookeeper1.perform(); zookeeper1.perform(); zookeeper1.perform(2) } }
Zookeeper继承自AbstractAnimal,而它的父亲AbstractAnimal很聪明,它把getInstance()覆盖为抽象方法,出于害怕把buyAnimals()权限设置成protect,并且覆盖Animal中的perform方法并规定perform无法再被它子类覆盖。继承后的Zookeeper知道父亲的用意,但公开地购买很多的Animal,实现了父亲的getInstance,让买来的Animal轮流替他perform,并且又重载出很多花样的perform。
重载和覆盖做了什么?
个人觉得:
覆盖做的是去掉层层继承与实现中会被java虚拟机认为是同一个函数的。
重载做的是如何让虚拟机认识这两个函数虽然名称相同,但实质不同。
我们看一行很常用的代码:a.f(argv), 其中a为某个实例对象,f为方法名,argv为若干个参数或者空
假如我们重写父类中的方法不会被覆盖掉,按照继承可以获得父类所有可访问的方法,那么子类中将会有两个方法假设名为f,且参数列表相同,那么调用f时该如何抉择呢?显然只给的a,f,argv三个参数虚拟机无法去抉择,必须覆盖掉一个。但是我们确实有写几个名称相同的方法的需求,此时a和f都是相同的,那么只有通过argv来区分了,这个过程大概就是重载吧。
先看函数名相同各种的情况:
1.参数列表(参数列表指参数类型顺序,个数) 2.final修饰 3.权限修饰符 4.返回值类型 5.abstract修饰
函数重载时可以发生在本类中和本类与父类中,本类与父接口的默认方法中,参数列表必定不同,和final修饰,权限修饰,返回值类型,abstract修饰无关系。
方法覆盖只能发生在子类与父类或子类与父接口的默认方法间,函数名相同,参数列表相同,返回值类型可以不同但必须是其原类型的子类,不能覆盖final修饰的方法,abstract修饰符符合java规范即可。
几种特别注意的函数名相同:
1.子类覆盖父类方法do()时,提高了该方法的权限:
Father f = new Son(); f.do() // 因为Son中权限的提高导致do()无法调用
2.参数列表相同,但返回值不是父类中定义类型或其子类
Father f = new Son() 方法重名。 A a = f.getA() //因为被Son覆盖为返回B类型,这不是坑爹吗?
3.参数列表相同,返回值是父类中定义类型的子类
此时Father f = new Son() A a = f.getA() 形如A a = new B() 形如Father f = new Son() ,没毛病.
4.抽象实现, 将父类方法改为抽象实现
此时子类必定是个抽象类,其抽象实现的父类方法将由子类的子类实现。没毛病。
5.与父类方法参数列表不同,返回值相同。
我给你三个参数,你却去调用父类两个参数的方法?显然是重载。
总结
一个对象实例中有名称相同的两个方法,若参数列表相同,且两方法不在同一类中,要么是覆盖要么是不符合java规范;若参数列表不同,要么是重载,要么是不符合java规范。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java并发编程之深入理解线程池原理及实现
Java线程池在实际的应用开发中十分广泛。虽然Java1.5之后在JUC包中提供了内置线程池可以拿来就用,但是这之前仍有许多老的应用和系统是需要程序员自己开发的。因此,基于线程池的需求背景、技术要求了解线程池原理和实现,一方面可以更为深刻理解Java多线程开发,有助于解决业务系统中因为线程问题所产生的bug;另一方面也有利于对遗留代码的重构。 如果需要先行了解Java并发编程的基础知识,可参考以下随笔: 1.Java并发编程之线程创建和启动(Thread、Runnable、Callable和Future) 2.Java并发编程之线程生命周期、守护线程、优先级、关闭和join、sleep、yield、interrupt 3.Java并发编程之线程安全、线程通信 4.Java并发编程之ThreadGroup 线程池原理 所谓的线程池,跟JDBC连接池、代理池等一样,属于一种“池”的设计模式。在设计好的数据结构中存放一定数量的线程,并且根据任务需要自动调整线程数量的多少,直到峰值。具体说来,线程池需要满足若干条件: 1. 任务队列:用于缓存提交的任务 2. QueueSize:任务队列存放的...
- 下一篇
JavaScript学习(八)
目录 对象分类: 1.内建对象: 2.宿主对象: 3.自定义对象: javascript内部对象 FileSystemObject对象 动态创建FileSystemObject对象 FileSystemObject对象的方法 In 运算符 JS数据类型 对象字面量 函数: 对象分类: 1.内建对象: 由ES标准中定义的对象,在任何ES中都可以使用 ----比如:math,string,number,Boolean 2.宿主对象: 由JS的运行环境提供的对象,目前来讲主要指浏览器提供的对象 比如:BOM,DOM 3.自定义对象: 由开发人员自己创建的对象 javascript内部对象 对象属于复合的数据类型。 FileSystemObject对象 在javascript中实现文件操作功能,主要是依靠FileSystemObject对象。该对象用来创建、删除和获得有关信息,还可以用来操作驱动器、文件夹和文件的方法和属性。 动态创建FileSystemObject对象 要想对文件进行相应的操作,首先需要对FileSystemObject对象进行实例化,也就是动态创建FileSystemObj...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8编译安装MySQL8.0.19
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题