如何理解多态,让我们举个例子来描述一下,因为单纯的说多态大家可能不理解:

 abstract class Animal
{ public int age = ; abstract void eat(); public void run()
{ System.out.println("I Run!"); } } class Dog extends Animal
{ public void eat()
{ System.out.println("I eat meat"); } public void lookUpHome()
{ System.out.println("I can look up home~"); } } class Cat extends Animal
{ public void eat()
{ System.out.println("I can eat Mouse"); } public void catchMouse()
{ System.out.println("I can catch Mouse"); } } class DuoTaiDemo1
{ public static void main(String[] args) { Dog d = new Dog();
Cat c = new Cat();
d.eat();
c.eat(); } }

我们一般的思路在写DuoTaiDemo1这个类的时候,我们会通常这个样子写,但是我们发现我们这样子写是不是有点重复,同时new了一个继承自同一父类的子类,同时调用了继承自父类的方法。但是java是一种纯面向对象的语言,面向对象的特点是提高代码的复用性。java为了提高代码的复用性,提供了一下的写法:

 class DuoTaiDemo1
{ public static void main(String[] args) { eat(new Dog());
eat(new Cat()); } public static void eat(Animal a)
{ a.eat(); } }

这个样子的话,我们仅需要传一个对象进去就能够,调用相关方法,这样是不是提高了代码的复用性呢?

在这里需要注意的一点是DuoTaiDemo1这个类的eat方法接受的参数是Animal型的,同时Dog 和 Cat也是继承自Animal的是其子类,所以这样写是合法的。那么也就是说,这个时候Cat即属于动物也属于猫,同时具有两种形态,这个就是面向对象当中所说的多态。

多态更形象一些可以这样子来写:

 Animal c = new Cat();//一个对象两种形态

等式两边分属两个不同的类,具有不同的形态,右边继承自左边。

定义:多态就是某一类事物存在的多种形态。多态在代码中的体现:父类或者接口的引用指向其子类的对象。

多态的好处:

  提高了代码的扩展性,前期定义的代码可以使用后期的内容。 这句话的好处在于,在前期定义的代码里面可以使用后期的内容,比如上述定义的猫啊、狗啊继承自动物类,在DuoTaiDemo1中的eat方法当中我们使用Animal类型的作为传入参数。这个时候我们可以定义一个猪类然后也让他继承自动物,这样子我们就可以在DuoTaiDemo1当中利用以前定义的方法,然后直接传入猪的对象,代码体现如下:

  

 class Pig extends Animal
{ public void eat()
{ System.out.println("I can eat grass!"); } public void gongDi()
{ System.out.println("I can gong earth"); } } class DuoTaiDemo1
{ public static void main(String[] args) { eat(new Dog());
eat(new Cat());
eat(new Pig());
} public static void eat(Animal a)
{ a.eat(); } }

这样就叫做前期定义的代买可以使用后期定义的内容。

那么多态有哪些弊端呢?我们仍然用代码来体现:

 class DuoTaiDemo1
{ public static void main(String[] args) { eat(new Dog());
eat(new Cat());
eat(new Pig());
} public static void eat(Animal a)
{ a.eat();
a.catchMouse();//这样子写是错误的,因为父类当中并没有定义这个方法
} }

这里如果我们用传入的Animal a 对象来调用catchMouse()这个方法的话,就会报错,为什么因为Animal这个抽象类当中并没有预先定义这个方法,这个方法是子类的特有的方法,所以调用的时候就会报错。这个就是多态的局限性。

多态的缺陷:

  前期定义的代码不能调用后期内容的特有方法

使用多态的前提:

  1、必须有关系,继承或这实现。

  2、必须有覆盖。

我们把代码现在改成这个样子:

 class DuoTaiDemo1
{ public static void main(String[] args) { Animal a = new Cat();
a.eat();//
a.catchMouse();
} public static void eat(Animal a)
{ a.eat();
a.catchMouse();//
} }

我们知道在

 byte a = ;int x = a;//这个过程当中发生了自动类型提升。

同样在多态当中,也发生了自动类型的提升。子类型提升为父类型并且屏蔽掉了子类型当中特有的方法,限制对特有功能的使用。这种方式也叫做向上转型。如果我们想用子类当中特有的功能方法,我们必须向下转型。我们继续上述的代码:

 class DuoTaiDemo1
{ public static void main(String[] args) { Animal a = new Cat();//向上转型限制了对子类当中特有功能的访问
a.eat();//
Cat b = (Cat)a;//向下转型是为了访问子类当中特有的方法
/**对于转型,自始至终都是在对子类的类型做变化,同时也需要注意,狗
*只能对狗的对象引用做向下转型,一个类只能对其属于他的对象向下转型
*比如Cat b = (Dog)a;这种写法就是完全错误的,因为属于猫的怎么样也不
*可能变成狗。
*/
b.catchMouse();
} }

instanceof的使用

那么上述我们也讲过了,一个类型只能针对一个类型的引用做相应的判断。这个时候我们会发现在我们写主方法当中的eat方法的时候,要调用子类型对象的特有方法就会非常棘手,因为我们传入的是Animal这个父类的对象,这个是不确定的性的,可能未向上转型之前,我们的对象可能是狗、猫、猪,那么我们怎么判断如何向下转型,利用子类当中特有的方法呢?也就是说,这里我们需要做的一个就是如何判断一个对象到底属于哪个类的问题,这里我们就用到了instanceof这个关键字。这个关键字有什么作用呢,这个关键字的作用就在于能够帮我们判断一个对象到底属于那个类。代码示例:

 class DuoTaiDemo1
{ public static void main(String[] args) { Animal a = new Cat();
if(a instanceof Animal)
System.out.println("a is an instance of Animal");
else
System.out.println("a isn't an instance of Animal");
if(a instanceof Cat)
System.out.println("a is an instence of Cat");
else
System.out.println("a isn't an instance of Cat"); } }

在上述的代码当中,我们可以知道,一个类的对象是该类的实例,同样也属于该类往上的父类的实例。这样我们就可以改良之前我们写的方法:

 class DuoTaiDemo1
{ public static void main(String[] args) { Animal a = new Dog();
method(a);
} public static void method(Animal a)
{ a.eat();
if(a instanceof Cat)
{
Cat b = (Cat)a;
b.catchMouse();
}
else if (a instanceof Dog)
{
Dog b = (Dog)a;
b.lookUpHome();
}
else
{
Pig b = (Pig)a;
b.gongDi();
} } }

在想使用子类当中特有的方法时,一定要向下转型。当想屏蔽掉子类当中的特有方法,想使用父类当中定义的基本的方法时,就可以用向上转型,屏蔽掉子类当中特有的方法。

多态时,成员的特点:

  成员变量:

    编译时,参考引用型变量所属类型当中是否有该成员变量,如果有编译通过,如果没有编译失败。

    运行时,也是参考引用型变量所属类型当中是否有该成员变量,并运行该所属类的成员变量。

    简单说:编译和运行都参考等号的左边。

  

 class Fu
{ int num = ; } class Zi extends Fu
{ int num = ; } class DuoTaiDemo2
{ public static void main(String[] args) { /**
*引用型变量a 所属类型为Fu所以a调用num这个成员变量的时候,是参考Fu类来
*去确定的
*/
Fu a = new Zi();//
Zi b = new Zi();//
System.out.println(a.num);
System.out.println(b.num); } }

如果Fu类当中没有num这个成员变量的话,那么编译的时候,就会提示找不到符号num的错误。如果编译通过运行的时候,会参考应用型变量a所属的类型也就是Fu类型当中的成员变量num来调用。这个是基于什么原理呢,因为我们知道在初始化的时候,Zi的初始化,在内存空间当中成员变量是分两个部分的一个是this指想本类当中的成员变量,还有一个super关键字指向父类的成员变量,因为成员变量是共存的不存在覆盖关系,只有方法有覆盖的关系。

  成员方法:

  实例代码:

  

 class Fu
{ void show()
{ System.out.println("Fu show"); } } class Zi extends Fu
{ void show()
{ System.out.println("Zi show"); } } class DuoTaiDemo3
{ public static void main(String[] args) { Fu f = new Zi();
f.show();//zi show } }

我们来画个内存图来理解下多态时候成员方法的调用是怎样的?

在我们创建子类对象的时候,我们知道在堆内存当红分配一个内存空间,之后主方法进栈,然后调用show方法,这个时候因为f是一个指向堆内存当中先前的对象的地址。所以在调用的时候,这个时候this绑定的对象就是之前创建的对象,因为成员方法是依赖于对象的,所以这个时候调用show就会去f指向地址所属类的方法区去寻找方法,如果找到了就调用这个方法如果没有找到就会去父类当中寻找。

以为我们知道多态对应的一类对象不一定固定,因为就像之前说的动物类型的引用变量可能是狗、可能是猪,这些只能够在运行的时候,才能实时的调用指定类型的成员方法,这个中方式也叫做动态绑定。

那么成员函数的特点是什么呢?

  编译时:参考引用型变量所属的类当中是否有指定的成员方法,有的话编译通过,没有的话编译失败。

  运行时,参考成员方法所属的类,而非父类,如果子类当中有方法,就进行调用,如果没有才会调用父类当中的方法。

  简单说:编译看左边,运行看右边。

静态方法:

  编译时:参考所属类当中是否有相应的静态方法。

  运行时:参考所属类当中是否有相应的静态方法。

  简单说:编译和运行都看左边。

这个为什么是这个样子的呢?因为我们知道静态方法的存在是不依赖于对象的,他是先于对象而存在的,所以说调用成员方法没有必要创建对象。直接使用就可以了,不需要绑定到指定的对象上面。

java学习面向对象之多态的更多相关文章

  1. Java学习---面向对象的远程方法调用[RMI]

    基础知识 分布式计算是一门计算机科学,它研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给许多计算机进行处理,最后把这些计算结果综合起来得到最终的结果. 常见的分 ...

  2. java学习面向对象之异常之一

    一.异常的概述: 什么是异常?在我们编写java程序的时候,会出现一些问题,比如内存溢出啊或者数组索引超出最大索引啊,这些编程当中出现的这些个问题就是异常.但是异常也分为可以处理的和不可以处理的.比如 ...

  3. [Java学习]面向对象-多态

    多态 多态发生条件 发生在有继承关系的类型中. 向上转型(自动类型转换)与向下转型(强制类型转换) //向上转型 //编译阶段a1被编译器看作是Animal类型,所以a1引用绑定的是Animal类中的 ...

  4. java学习面向对象之匿名内部类

    之前我们提到“匿名”这个字眼的时候,是在学习new对象的时候,创建匿名对象的时候用到的,之所以说是匿名,是因为直接创建对象,而没有把这个对象赋值给某个值,才称之为匿名. 匿名对象回顾: class N ...

  5. java学习--面向对象

    对象及类的概念 对象是java程序的核心,在java程序中“万事万物皆对象” 对象可以看成是属性和方法的封装体 类是用来创建同一类型的对象的模板,在一个类中定义了该类对象所应具有的属性和方法 J2SD ...

  6. Java学习 面向对象(下)——Java疯狂讲义th4

    面向对象(下) [TOC] 包装类 通过包装类可以把8个基本类型的值包装成对象使用. 自动拆箱.自动装箱 把字符串类型值转换成基本类型的值: 包装类的 parseXxx(String s)静态方法 包 ...

  7. java学习笔记(4)多态

    一.多态 --------------------------------------------- 1.定义:某一类事物的多种存在形态 例如:动物中猫,狗. 猫这个对象对应的类型是猫类型 猫 x  ...

  8. java学习面向对象之内部类

    什么是面向对象内部类呢?所谓的内部类,即从字面意义上来理解的话,就是把类放到类当中. 那么内部类都有什么特点呢? 1.内部类可以访问包裹他的类的成员. 2.如果包裹他的类想访问被其包裹的类的话就得实例 ...

  9. java学习面向对象之接口

    上一节当中我们说道抽象类,抽象类当中的方法可以是抽象的也可以是非抽象的,那么当抽象类中所有方法都是抽象的时候,我们就可以把它重新定义为接口.代码示例: abstract class Animal { ...

随机推荐

  1. JDK1.8 Lambda

    1.模拟Model /** * Author:JsonLu * DateTime:16/12/8 14:01 * Email:jsonlu@qq.com * Desc: */ public class ...

  2. 每日陌生php函数

    1,date_default_timezone_set(PRC) 设定一个脚本中所有日期函数的默认时区,PRC设置中国时区 2,microtime(true) 返回当前unix微秒时间戳 139868 ...

  3. Attribute 特性

    转载   不错   摘要:纠结地说,这应该算是一篇关于Attribute 的笔记,其中的一些思路和代码借鉴了他人的文笔(见本文底部链接).但是,由于此文对Attribute 的讲解实在是叫好(自夸一下 ...

  4. asp IIS部署An error occurred on the server when processing the URL错误提示解决

    An error occurred on the server when processing the URL. Please contact the system administrator.If ...

  5. 消除热块(hot block)

    上篇日志提到了,那么高的负载,是存在数据块读竞争,下面介绍几个方法来消除块竟争 查找块竟争 SELECT p1 "file#", p2 "block#", p3 ...

  6. EA UML 建模——类图

    Enterprise Architect(EA) 是一个功能比较强悍的建模工具,本篇文章仅使用其 UML 建模功能,其他更多功能,可以Google. 一.简单梳理C#中类与类.类与接口.接口与接口的关 ...

  7. WampServer修改MySQL密码

    WampServer安装后密码是空的,需要设置一下 一般有两种方式: 一是通过phpMyAdmin直接修改: 二是使用WAMP的MySql控制台修改. 第一种: ①在phpMyAdmin界面中点击[用 ...

  8. 一个由IsPrime算法引发的细节问题

    //******************************* // //    2014年9月18日星期四,于宿舍撰写 //    作者:夏华林 // //******************* ...

  9. Linux + C + Epoll实现高并发服务器(线程池 + 数据库连接池)(转)

    转自:http://blog.csdn.net/wuyuxing24/article/details/48758927 一, 背景 先说下我要实现的功能,server端一直在linux平台下面跑,当客 ...

  10. 网站访问架构cdn与负载均衡

    曾经见到知乎上有人问“为什么像facebook这类的网站需要上千个工程师维护?”,下面的回答多种多样,但总结起来就是:一个高性能的web系统需 要从无数个角度去考虑他,大到服务器的布局,小到软件中某个 ...