java学习面向对象之多态
如何理解多态,让我们举个例子来描述一下,因为单纯的说多态大家可能不理解:
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学习面向对象之多态的更多相关文章
- Java学习---面向对象的远程方法调用[RMI]
基础知识 分布式计算是一门计算机科学,它研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给许多计算机进行处理,最后把这些计算结果综合起来得到最终的结果. 常见的分 ...
- java学习面向对象之异常之一
一.异常的概述: 什么是异常?在我们编写java程序的时候,会出现一些问题,比如内存溢出啊或者数组索引超出最大索引啊,这些编程当中出现的这些个问题就是异常.但是异常也分为可以处理的和不可以处理的.比如 ...
- [Java学习]面向对象-多态
多态 多态发生条件 发生在有继承关系的类型中. 向上转型(自动类型转换)与向下转型(强制类型转换) //向上转型 //编译阶段a1被编译器看作是Animal类型,所以a1引用绑定的是Animal类中的 ...
- java学习面向对象之匿名内部类
之前我们提到“匿名”这个字眼的时候,是在学习new对象的时候,创建匿名对象的时候用到的,之所以说是匿名,是因为直接创建对象,而没有把这个对象赋值给某个值,才称之为匿名. 匿名对象回顾: class N ...
- java学习--面向对象
对象及类的概念 对象是java程序的核心,在java程序中“万事万物皆对象” 对象可以看成是属性和方法的封装体 类是用来创建同一类型的对象的模板,在一个类中定义了该类对象所应具有的属性和方法 J2SD ...
- Java学习 面向对象(下)——Java疯狂讲义th4
面向对象(下) [TOC] 包装类 通过包装类可以把8个基本类型的值包装成对象使用. 自动拆箱.自动装箱 把字符串类型值转换成基本类型的值: 包装类的 parseXxx(String s)静态方法 包 ...
- java学习笔记(4)多态
一.多态 --------------------------------------------- 1.定义:某一类事物的多种存在形态 例如:动物中猫,狗. 猫这个对象对应的类型是猫类型 猫 x ...
- java学习面向对象之内部类
什么是面向对象内部类呢?所谓的内部类,即从字面意义上来理解的话,就是把类放到类当中. 那么内部类都有什么特点呢? 1.内部类可以访问包裹他的类的成员. 2.如果包裹他的类想访问被其包裹的类的话就得实例 ...
- java学习面向对象之接口
上一节当中我们说道抽象类,抽象类当中的方法可以是抽象的也可以是非抽象的,那么当抽象类中所有方法都是抽象的时候,我们就可以把它重新定义为接口.代码示例: abstract class Animal { ...
随机推荐
- C# 的可空合并运算符(??)到底是怎样的宝宝?
前言废语 也怪自己小白和不勤奋,没有系统的学习C#相关的东西,工作一年多还是初级小菜,深感不安,来到园子才发现好多钻研技术的人,也渐渐发现自己开始喜欢上了这个编程的世界.今日偶遇??操作符,发现我只看 ...
- 验证jquery.validate.js
<pre>jquery.validate.js使用之自定义表单验证规则,下面列出了一些常用的验证法规则 jquery.validate.js演示查看 <a href="ht ...
- jq版本更新后无live函数的处理.
之前你的代码如果是$("#ele").live("click", function() { //...});现在要写成$("#ele" ...
- Nico Game Studio 2.设置页面读写 纹理载入与选择
进度十分之慢... 配置读写一样采用之前写的自动绑定的方法: 分享一下代码: SetControl是把数据写到control上的. SetObject是把数据写到对象上 GetData是从控件读取数据 ...
- SQL生成一柱双色球
数据库环境:SQL SERVER 2005 以前用C/JAVA穷举双色球的所有排列,今天想着换成用SQL实现,只生成一柱双色球. 简单说下双色球的规则,双色球由红色球和蓝色球组成,每注投注号码由6个红 ...
- Windows服务安装方法
操作系统:Win8.1 安装方法:在命令行窗口中输入:InstallUtil service.exe 出错原因:需要以管理员身份启动命令行.
- CocoaPods详解之----进阶篇
作者:wangzz原文地址:http://blog.csdn.net/wzzvictory/article/details/19178709转载请注明出处如果觉得文章对你有所帮助,请通过留言或关注微信 ...
- NoSql之Redis使用(一)
一.安装 1.下载安装包: 官方网站:redis.io 官方推荐windows版本:https://github.com/MSOpenTech/redis 2:下载压缩包,解压后如下 redis-se ...
- gpfdist工具的初级使用
gpfdist工具的使用主要两步: 第一步:打开gpfdist服务: gpfdist -d /home/admin -p -l /tmp/gpfdist.log & 参数解释: -d 数据文件 ...
- C#中Socket用法,多个聊天和单一聊天。
自己琢磨Socket刚刚几天,所以整理出来和大家共享一下.废话少说直接进入正题. 在C#中提供了两种网络服务,一种是Socket类,另一种是TcpListener(服务器),TcpClient(客户端 ...