多态

面向对象编程有三大特性:封装、继承、多态。

封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。

继承是为了重用父类代码。两个类若存在IS-A的关系就可以使用继承。,同时继承也为实现多态做了铺垫。(我的关于继承的博客http://www.cnblogs.com/yangliguo/p/7481550.html)

多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

例子:

父亲person有行为这个方法,里面包括几个动作:吃饭,睡觉,走路 父亲有三个儿子,三个儿子都继承了父亲的行为方法,所以三个儿子都有吃饭,睡觉,走路这些动作,但是三个儿子又分别有自己的动作--大儿子A会弹吉他,二儿子B会唱歌,三儿子C会打鼓 ...

1.Person person = new A(); 不是父类对象指向子类引用而是父类引用指向子类对象

2.这个对象不能调用子类A特有的弹吉他方法--person.guitar();

3.如果仅是这么写程序,还不是多态,记住实现多态的三要素:继承 重写 父类引用指向子类对象

4.之后,如果你调用persion.guitar(),此时在代码的编译阶段,persion调用的仍然是自己的guitar(),不是儿子的。而当程序运行时,就是java XXX, persion调用的却是儿子的guitar()。这个动态的过程才是多态 。

Person person;

//父类的引用指向子类的方法;

person = new Student();

//person类型引用做一个判断

//(1)if(person.eat().size==2 )

{

if(person instanceof Person)

{

person.eat();

}else if(person instanceof Student) {

Student stu = (Student)person;

stu.eat();

}

person.eat();//从代码角度看,此时是父类的引用调用的是父类中的eat方法

//(2)子类若覆盖了父类的方法,eat动态绑定到父类的引用Person上,换个名字叫动态绑定

//父类的引用可以调用子类的方法,我们把这一现象成为多态

//从字面意思来理解person这个父类的引用一会是person一会是student

//person有多种状态;

//也叫方法的动态绑定

//继承是通向多态的入口

person.f2();

person.gotobed();

person.eat();

Student stu = new Student();

stu.eat();

stu.gotobed();

//父类的引用能够调用子类的方法

}

注:

在继承中对象方法的调用的优先级:

this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

即先查this对象的父类,没有就重头再查参数的父类

多态的概念

多态的定义

指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)

实现多态的技术

实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

多态存在的三个必要条件

继承:在多态中必须存在有继承关系的子类和父类。

重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。

向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。

对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。即超类可是使用子类方法,但不能调用父类同名方法。

多态的优点

1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。

2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。

3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。

4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。

5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

多态的实现方式

接口实现,继承父类进行方法重写,同一个类中进行方法重载。

例子:这个例子比较好是从知乎上看到的链接。

首先我们定义两个类,一个父类Animal,一个子类Cat。

父类Animal

class Animal {

int num = 10;

static int age = 20;

public void eat() {

System.out.println("动物吃饭");

}

public static void sleep() {

System.out.println("动物在睡觉");

}

public void run(){

System.out.println("动物在奔跑");

}

}

子类Cat

class Cat extends Animal {

int num = 80;

static int age = 90;

String name = "tomCat";

public void eat() {

System.out.println("猫吃饭");

}

public static void sleep() {

System.out.println("猫在睡觉");

}

public void catchMouse() {

System.out.println("猫在抓老鼠");

}

}

测试类Demo_Test1

class Demo_Test1 {

public static void main(String[] args) {

Animal am = new Cat();

am.eat();

am.sleep();

am.run();

//am.catchMouse();这里先注释掉,等会会说明

//System.out.println(am.name);//这里先注释,待会说明

System.out.println(am.num);

System.out.println(am.age);

}

}

以上的三段代码充分体现了多态的三个前提,即:

1、存在继承关系

Cat类继承了Animal类

2、子类要重写父类的方法

子类重写(override)了父类的两个成员方法eat(),sleep()。其中eat()是非静态的,sleep()是静态的(static)。

3、父类数据类型的引用指向子类对象(向上转型)。

测试类Demo_Test1中 Animal am = new Cat();语句在堆内存中开辟了子类(Cat)的对象,并把栈内存中的父类(Animal)的引用指向了这个Cat对象。到此,满足了Java多态的的必要三个前提。

运行结果:

猫吃饭。

动物在睡觉

动物在奔跑

10

20

可以看出来

子类Cat重写了父类Animal的非静态成员方法am.eat();的输出结果为:猫吃饭。

子类重写了父类(Animal)的静态成员方法am.sleep();的输出结果为:动物在睡觉

未被子类(Cat)重写的父类(Animal)方法am.run()输出结果为:动物在奔跑

System.out.println(am.num);//输出结果为10

System.out.println(am.age);//输出结果为20

多态成员访问的特点

那么我们可以根据以上情况总结出多态成员访问的特点:

成员变量

编译看左边(父类),运行看左边(父类)

成员方法

编译看左边(父类),运行看右边(子类)。动态绑定

静态方法

编译看左边(父类),运行看左边(父类)。(静态和类相关,算不上重写,所以,访问还是左边的)只有非静态的成员方法,编译看左边,运行看右边

多态弊端

即多态后不能使用子类特有的属性和方法。往上面的代码看,子类Cat有一个特有的属性String name = "tomCat"; 并且还有一个特有的抓老鼠的方法catchMouse()。但是在测试类(Demo_Test)中,我们尝试调用子类特有的方法catchMouse()和打印子类特有的成员属性String name = "tomCat"; 就会报错。

am.catchMouse();

System.out.println(am.name);

原因就是多态的弊端,就是:不能使用子类特有的成员属性和子类特有的成员方法, 因为调用method方法的时候首先回去找父类中有没有这个方法 结果父类中没有这个方法所以就会报错。

同时父类可以使用子类方法,但不能直接调用父类同名方法。上面的例子有体现的如,am不能调用父类的eat输出“动物吃饭”。如果子类方法确实想访问父类中被隐藏的同名字段,可以用super关键字来访问它。

解决方法

如果在代码执行过程中还想使用Cat类中特有的属性String name和它特有的成员方法catchMouse()了怎么办呢?那我们就可以把这个父类引用指向了子类对象的家伙am再强制变回Cat类型。这样am就是Cat类型的引用了,指向的也是Cat对象了,自然也能使用Cat类的一切属性和一切的成员方法。

class Demo_Test {

public static void main(String[] args) {

Animal am = new Cat();

am.eat();

am.sleep();

am.run();

//am.catchMouse();

//System.out.println(am.name);

System.out.println(am.num);

System.out.println(am.age);

System.out.println("------------------------------");

Cat ct = (Cat)am;

ct.eat();

ct.sleep();

ct.run();

ct.catchMouse();

}

}

运行结果:

猫吃饭

猫在睡觉

动物在奔跑

猫在抓老鼠

很明显,执行强转语句Cat ct = (Cat)am;之后,ct就指向最开始在堆内存中创建的那个Cat类型的对象了。这就是多态的魅力吧,虽然它有缺点,但是它确实十分灵活,减少多余对象的创建,不用说为了使用子类的某个方法又去重新再堆内存中开辟一个新的子类对象。

再来个例子:

毕竟这块还是比较难理解的,这个例子大家可以看看,帮助大家加深印象。把那个总结多看看,看运行是到底要看子类还是父类(超类)

public class A {

public String show(D obj) {

return ("A and D");

}

public String show(A obj) {

return ("A and A");

}

}

public class B extends A{

public String show(B obj){

return ("B and B");

}

public String show(A obj){

return ("B and A");

}

}

public class C extends B{

}

public class D extends B{

}

public class Test {

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

在这里看结果1、2、3还好理解,从4开始就开始糊涂了时,可以看下第一个例子下面的注,哪里我写了继承链中对象方法的调用的优先级。

这个例子看不懂的话可以看下原文里面有详细解析

链接为:http://www.cnblogs.com/chenssy/p/3372798.html

java面向对象的多态_java面向对象(五)之多态相关推荐

  1. java 多态_Java面向对象 —— 多态

    前两天已经相继介绍了Java面向对象的三大特性之中的封装.继承,所以今天就介绍Java面向对象的三大特性的最后一项,多态~ 首先讲一下什么是多态,以及多态需要注意的细节 什么是多态:一个对象具备多种形 ...

  2. java面对对象教学_Java面向对象程序设计教与学

    原标题:Java面向对象程序设计教与学 面向对象程序设计(Object Oriented Programming,OOP)主要研究如何从对象的角度出发构建程序单元以及程序开发机制,主要内容包括抽象的技 ...

  3. java类的心得_java面向对象学习心得3篇

    日记网 >> 专题 java面向对象学习心得3篇 更新时间:2018/6/15 8:27:00  点击率:937  手机版 java面向对象学习心得3篇来自简单日记网精选推荐.在面向对象的 ...

  4. java面向对象基本特征_Java 面向对象的基本特征

    前言: 在刚开始接触Java的时候,那时候面对Java面向对象的几大特征一直理解的不是很理解,借着空闲时间在这里整理一下,同时在加深一下印象. 一.封装: Java面向对象的特征之封装,所谓的封装就是 ...

  5. java面向对象的教程_java面向对象入门教程

    java面向对象入门教程 Java 编程语言的风格十分接近C.C++语言.Java是一个纯的面向对象的程序设计语言,以下是小编为大家搜索整理的java面向对象入门教程,希望能给大家带来帮助!更多精彩内 ...

  6. java公社博客_Java面向对象开发学习笔记(一)

    Java面向对象开发 共105课时 课时1 面向对象简介 面向对象是一种程序设计方法,但是并不是所有开发者都认同面向对象,因为很多开发者认为面向对象过于复杂,所以更多人愿意使用函数式编程. 面向对象的 ...

  7. java 多态_Java基础深度总结:多态

    你我皆风华正茂,梦死方坠人生暮年 1.什么是多态 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪 ...

  8. java 抽象封装多态_java面向对象(封装,继承,多态,抽象,接口的定义和实现)...

    1.封装 在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装.隐藏起来的方法. 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定 ...

  9. java 对象的态_Java面向对象-------多态总结

    1.多态:是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作,如图所示: 多态性是对象多种表现形式的体现. 2.多态作用: 1. 消除类型之间的耦合关系 ...

最新文章

  1. Java Web知识梳理
  2. sed和awk有什么区别? [关闭]
  3. Android自定义View的实现方法,带你一步步深入了解View(四)
  4. 到底什么是跨域?附解决方案!
  5. html:(39):块级元素和内联块级元素
  6. HTTP Get Post
  7. Java基础02 位运算符<<、>>
  8. 三星可折叠手机Galaxy F再曝光 外观酷炫设计出色
  9. F5补丁修复及几点命令
  10. 查看自己电脑上某个端口有没有被占用
  11. Java 9 ← 2017,2019 → Java 13 ,Java 两年来都经历了什么?| CSDN 博文精选
  12. 大数据时代下的用户洞察(转载)
  13. 自定义百度网盘分享密码提取码
  14. 复选框点击后弹出输入框
  15. c语言满屏爱心,微信聊天可以发满屏动态爱心了 个性又浪漫!
  16. 【Oracle】存储过程基本语法
  17. 关于人工智能神经网络机器人的动画
  18. NovAtel 板卡OEM617D配置步骤记录
  19. 什么是缓存穿透、缓存雪崩、缓存击穿
  20. irsend 树莓派 php,使用树莓派(Raspberry Pi)实现智能家居(3/4)

热门文章

  1. 【Python】文件的使用
  2. C 语言实例 - 输出九九乘法口诀表
  3. 一个数据包的旅程_数据科学语言的个人旅程
  4. Visual Studio 2017配置CTP的API文件
  5. Simulink_Debug的使用
  6. 浅说深度学习(1):核心概念
  7. 浏览器兼容之JavaScript篇——已在IE、FF、Chrome测试
  8. 看完就会明白windows RT推出的原因、它和window 8到底有些什么区别、微软有什么战略企图--有关于微软Windows RT 你不知道的那些事
  9. Android中的Handler总结
  10. 深度学习《CNN架构续篇 - 学习率衰减》