Java的多态浅谈
Java的多态浅谈
概述
Java的四大基本特性:抽象,封装,继承和多态。其中,抽象,封装,继承可以说多态的基础,而多态是封装,继承的具体表现。如果非要用专业术语来描述什么是多态的话
多态是指程序中定义的引用变量所指向具体类型和通过该引用变量发出的方法调用在编译的时候并不确定,而是程序运行期间才确定,就是说一个引用变量到底指向哪一个类的实例对象,该引用变量发出的方法调用哪一个类的中的方法,必须在程序运行期间才能确定。
记得大学时老师讲多态举的一个例子:上课铃响了,同学们都回各自教室上课,这就是多态。这就完了?如果是刚接触编程的同学来说,估计都懵逼了,我们那时就是这种状态。接下来我们用代码实现下老师说的意思。
多态实例
//上课铃响了
public class Ring
{
public void ringSound() { System.out.println("我是铃声!!!"); }
}
1班的同学听到铃声回去上语文课
public class ClassRoom1 extends Ring
{
public void ringSound() { System.out.println("classRoom1的同学听到铃声上语文了!!!"); }
}
2班的同学听到铃声回去上英语课
public class ClassRoom2 extends Ring
{
public void ringSound() { System.out.println("classRoom2的同学听到铃声上英语了!!!"); }
}
Main类
public class Main
{
public static void main(String[] args) { Ring ring = new ClassRoom1(); Ring ring1 = new ClassRoom2(); ring.ringSound(); ring1.ringSound(); }
}
输出
classRoom1的同学听到铃声上语文了!!!
classRoom2的同学听到铃声上英语了!!!
这就是一个简单的的多态例子,我们从中不难发现,多态存在的几个关键点,
有继承关系(extends)
子类重写父类方法(ringSound)
父类引用指向子类对象 Ring ring = new ClassRoom1()
现在我们改下例子,看出现什么情况
public class Ring
{
public static void ringSound() { System.out.println("我是铃声!!!"); }
}
这时发现ClassRoom1 和 ClassRoom2 都报错了,那我们也给他们都加上static
public class ClassRoom1 extends Ring
{
public static void ringSound() { System.out.println("classRoom1的同学听到铃声上语文了!!!"); }
}
ClassRoom2类
public class ClassRoom2 extends Ring
{
public static void ringSound() { System.out.println("classRoom2的同学听到铃声上英语了!!!"); }
}
预编译没报错了,那么输出应该是刚才的结果,main函数跑起来,输出
我是铃声!!!
我是铃声!!!
可以发现,结果并不是我们所想的那样。我们可以得出一个结论:在Java中static修饰的函数不能被子类重写。
其实Java中,父类含有一个静态函数,而且在他的子类也同样有一个返回类型,函数名,参数列表都相同的静态函数,子类实际上只是将父类中的该同名函数进行隐藏,而非重写,他们两个是完全没有关系的函数,所以他们的行为并不具有多态性。
注意:就是被final修饰的父类函数是无法被重写和private修饰的父类函数无法被继承。这是Java的规定,就不在举例说明
多态的作用
说了这么多,多态有什么作用
解耦,各种设计模式大多是基于多态实现的
复用性,子类处理父类即可
扩充和维护
多态缺点:不能使用子类的特有属性和行为。
多态分类
为了确定执行多态函数的哪一个,所以有两种情况:编译时多态,运行时多态
函数重载都是编译时多态,根据实际参数的数据类型,个数和顺序,Java在编译时就能够确定执行重载函数中的哪一个。
函数重写表现出两种多态性,当对象引用本类实例时,为编译时多态,否则为运行时多态。
public class Ring
{
public void ringSound() { System.out.println("我是铃声!!!"); }
}
Main类
public class Main
{
public static void main(String[] args) { ClassRoom2 ring1 = new ClassRoom2();//编译时多态,执行Ring类的ringSound ring1.ringSound(); //编译时多态,执行ClassRoom2 类的ringSound Ring ring = new ClassRoom2(); ring.ringSound(); //运行时多态,是运行Ring的 ringSound 还是 ClassRoom2 类的ringSound 只有运行时在确定。 }
花木兰替父从军(https://www.zhihu.com/question/30082151/answer/120520568)
花木兰替父亲花弧从军。那么这时候花木兰是子类,花弧是父类。花弧有自己的成员属性年龄,姓名,性别。花木兰也有这些属性,但是很明显二者的属性完全不一样。花弧有自己的非静态成员方法‘骑马杀敌’,同样花木兰也遗传了父亲一样的方法‘骑马杀敌’。花弧还有一个静态方法‘自我介绍’,每个人都可以问花弧姓甚名谁。同时花木兰还有一个自己特有的非静态成员方法‘涂脂抹粉’。但是,现在花木兰替父从军,女扮男装。这时候相当于父类的引用(花弧这个名字)指向了子类对象(花木兰这个人),那么在其他类(其他的人)中访问子类对象(花木兰这个人)的成员属性(姓名,年龄,性别)时,其实看到的都是花木兰她父亲的名字(花弧)、年龄(60岁)、性别(男)。当访问子类对象(花木兰这个人)的非静态成员方法(骑马打仗)时,其实都是看到花木兰自己运用十八般武艺在骑马打仗。当访问花木兰的静态方法时(自我介绍),花木兰自己都是用她父亲的名字信息在向别人作自我介绍。并且这时候花木兰不能使用自己特有的成员方法‘涂脂抹粉’。 -----------多态中的向上造型
那么终于一将功成万骨枯,打仗旗开得胜了,花木兰告别了战争生活。有一天,遇到了自己心爱的男人,这时候爱情的力量将父类对象的引用(花弧这个名字)强制转换为子类对象本来的引用(花木兰这个名字),那么花木兰又从新成为了她自己,这时候她完全是她自己了。名字是花木兰,年龄是28,性别是女,打仗依然那样生猛女汉子,自我介绍则堂堂正正地告诉别人我叫花木兰。OMG!终于,终于可以使用自己特有的成员方法‘涂脂抹粉’了。从此,花木兰完全回到了替父从军前的那个花木兰了。并且和自己心爱的男人幸福的过完了一生。 ------多态中的向下转型
花弧
public class HuaHu
{
int age = 60; String name = "花弧"; String sex = "男"; public void horseKillEnemy() { System.out.println("骑马杀敌"); } public static void suggest() { System.out.println("我叫花弧"); }
}
花木兰
public class HuaMuLan extends HuaHu
{
String name = "花木兰"; int age = 28; String sex = "女"; public void horseKillEnemy() { System.out.println("花木兰骑马杀敌"); } public void Prettify() { System.out.println("花木兰涂脂抹粉"); }
}
替父从军
public class Main
{
public static void main(String[] args) { //替父从军 HuaHu huaHu = new HuaMuLan(); System.out.println("姓名:" + huaHu.name + ",年龄:" + huaHu.age + ",性别:" + huaHu.sex); //其他人 huaHu.horseKillEnemy(); huaHu.suggest(); //用她父亲的名字信息在向别人作自我介绍 //huaHu.Prettify() //无法使用 // 战争结束了 HuaMuLan huaMuLan = (HuaMuLan)huaHu; //花木兰变回自己 System.out.println("姓名:" + huaMuLan.name + ",年龄:" + huaMuLan.age + ",性别:" + huaMuLan.sex); //自己特有函数 huaMuLan.Prettify(); System.out.println("幸福的过完了一生"); }
}
输出
姓名:花弧,年龄:60,性别:男
花木兰骑马杀敌
我叫花弧
姓名:花木兰,年龄:28,性别:女
花木兰涂脂抹粉
幸福的过完了一生
最后看个经典的多态例子
A类
public class A
{
public String show(D obj) { return ("A and D"); } public String show(A obj) { return ("A and A"); }
}
B类
public class B extends A
{
public String show(B obj){ return ("B and B"); } public String show(A obj){ return ("B and A"); }
}
C类
public class C extends B
{
}
D类
public class D extends B
{
}
Main类
public class Main
{
public static void main(String[] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println("1--" + a1.show(b)); System.out.println("2--" + a1.show(c)); System.out.println("3--" + a1.show(d)); System.out.println("4--" + a2.show(b)); System.out.println("5--" + a2.show(c)); System.out.println("6--" + a2.show(d)); System.out.println("7--" + b.show(b)); System.out.println("8--" + b.show(c)); System.out.println("9--" + b.show(d)); }
}
输出
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
你做对了吗?
原文地址https://www.cnblogs.com/dslx/p/10570559.html
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java异常被抛出或被捕获之后,代码是否继续执行的问题
在写程序的时候,我们经常被教导,要对异常的信息进行处理,哪里该抛出异常。但是,更多的时候,我们只是模仿异常的抛出,却不知道为什么要这样抛异常(被catch了?被向上抛了?后面的代码是否执行了?)。 接下来,我就简单的说一下异常抛出后的代码执行问题。此处不讨论自定义异常,因为自定义异常有自己的处理方式。 一、结论: 凡是有异常的地方,需要有处理异常的地方。(示例:Demo1, Demo2) 只要异常被处理,异常处理之后的代码都可以正常执行。(示例:Demo1, Demo2) 异常被往上抛出,则抛出异常之后的代码将不被执行。(示例:Demo2, Demo3) 二、示例代码 接下来用两段代码来说明异常抛出后代码执行的顺序 示例1. Demo1.java /** * 抛出异常的代码是放在 try 中 */ public class Demo1 {
- 下一篇
python基于opencv工具掌纹主线提取
我们将在这篇文章中使用Python和OpenCV库来找出我们手掌中的主线。 首先,让我们读取原始图像: import cv2 image = cv2.imread("palm.jpg") cv2.imshow("palm",image) #to view the palm in python cv2.waitKey(0) 现在我们将图像转换为灰度: gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) 现在我们将使用名为Canny Edge Detector的过滤算法来查找掌纹。 对于不同的图像,我们需要相应地更改参数。 edges = cv2.Canny(gray,60,65,apertureSize = 3) cv2.imshow("edges",edges) cv2.waitKey(0) 现在我们将反转颜色,以保证识别的线条是黑色的: edges = cv2.bitwise_not(edges) cv2.imshow("change black and white",edges) cv2.waitKey(0) 现在,我们将上面的图像与原始图像...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Linux系统CentOS6、CentOS7手动修改IP地址
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- CentOS7,CentOS8安装Elasticsearch6.8.6
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Red5直播服务器,属于Java语言的直播服务器
- CentOS6,CentOS7官方镜像安装Oracle11G
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池