# JAVA之旅(八)——多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例
* * *
> 学习是不能停止的
## 一.多态
> 我们今天又要学习一个新的概念了,就是多态,它是面向对象的第三个特征,何谓多态?
* 定义
> 某一类事物的多种存在方式
* 比如
> 动物中的猫狗,人类中的男人,女人
>
> 我们可以把多态理解为事物存在的多种体现形态
>
> 当我们new一个猫类的时候,和new 一个动物,其实是一样的,多种形态变现
>
> 所以我们可以分这几部分分析
* 1. 多态的体现
* 1. 多态的前提
* 3.多态的好处
* 4.多态的应用
> 我们定义一个需求,描述动物,正常的逻辑应该是这样描述的
~~~
//公共的 类 类名
public class HelloJJAVA {
// 公共的 静态 无返回值 main方法 数组
public static void main(String[] str) {
/**
* 动物: 猫,狗
*/
Cat c = new Cat();
c.eat();
dog d = new dog();
d.eat();
}
}
/**
* 动物
*
* @author LGL
*
*/
abstract class Animal {
// 吃什么不确定,抽象
abstract void eat();
}
/**
* 猫
*
* @author LGL
*
*/
class Cat extends Animal {
@Override
void eat() {
System.out.println("猫吃鱼");
}
}
/**
* 狗类
*
* @author LGL
*
*/
class dog extends Animal {
@Override
void eat() {
System.out.println("狗吃骨头");
}
}
~~~
> 这个体系我们展现出来一个为题,我们为了使用猫吃东西和狗吃东西,得new两个对象,要是多来几只小动物,我不还得new死,所以我们要想一个解决办法,他们有一个共性,就是都是动物,我们可以这样转换
~~~
Animal a = new Cat();
a.eat();
~~~
> 因为也是动物类型,我们输出
![这里写图片描述](http://img.blog.csdn.net/20160528165349402)
> 这就是多态在程序中的表现
* 父类的引用指向了自己的子类对象,这就是多态的代码体现形式,人 = new 男人,换句话说,父类的引用也可以接收子类的对象,所以我们可以这样定义一个方法
~~~
//公共的 类 类名
public class HelloJJAVA {
// 公共的 静态 无返回值 main方法 数组
public static void main(String[] str) {
/**
* 动物: 猫,狗
*/
AnimalEat(new Cat());
AnimalEat(new dog());
}
public static void AnimalEat(Animal a) {
a.eat();
}
}
~~~
> 这样就方便了,这样也就体现了多态的好处:
* 多态的出现大大的提升了程序的扩展性
> 但是有前提的
* 必须类与类之间有关系,要么继承,要么实现
* 通常,还有一个前提就是存在覆盖
> 不过,有利有弊,还是会存在弊端的
* 提高了扩展性,但是只能使用父类的引用访问父类的成员,这是局限性,但是我们侧重扩展性
> 我们再返回前面说多态的转型,我们看这段代码
~~~
//类型提升
Animal a = new Cat();
a.eat();
~~~
> 我们也叫作向上转型,
>
> 如果想要调属性,该如何操作(向下转型)?
* 强制将父类的引用转为子类类型
~~~
Animal a = new Cat();
a.eat();
Cat c = (Cat)a;
c.sleep();
~~~
![这里写图片描述](http://img.blog.csdn.net/20160528171943356)
> 也就是说,转型是强制将父类的引用,转为子类类型,向下转型。千万不要将父类对象转成子类对象,我们能转换的是父类引用指向子类对象的子类,多态自始至终都是子类对象在做着变化
>
> 那么你会了强转之后,你就说,我可以这样做
~~~
//公共的 类 类名
public class HelloJJAVA {
// 公共的 静态 无返回值 main方法 数组
public static void main(String[] str) {
/**
* 动物: 猫,狗
*/
AnimalEat(new Cat());
AnimalEat(new dog());
}
public static void AnimalEat(Animal a) {
a.eat();
Cat c = (Cat) a;
c.sleep();
}
}
~~~
> 这样是不是可以?我们看结果
![这里写图片描述](http://img.blog.csdn.net/20160528173936098)
> 这里报错了,提示的是狗类型不行转换成猫类型,的确,不能随便乱转。我们价格判断,怎么判断呢?条件语句该怎么写呢?这里我们又有一个关键字了**instanceof**
~~~
//公共的 类 类名
public class HelloJJAVA {
// 公共的 静态 无返回值 main方法 数组
public static void main(String[] str) {
/**
* 动物: 猫,狗
*/
AnimalEat(new Cat());
AnimalEat(new dog());
}
public static void AnimalEat(Animal a) {
a.eat();
//如果a的类型是Cat就执行
if(a instanceof Cat){
Cat c = (Cat) a;
c.sleep();
}
}
}
~~~
> 这样我们加了判断之后,我们就可以知道
![这里写图片描述](http://img.blog.csdn.net/20160528174201942)
> 既然多态说了这么多,我们来看看多态的应用吧,还是以一个需求开始去分析
~~~
//公共的 类 类名
public class HelloJJAVA {
// 公共的 静态 无返回值 main方法 数组
public static void main(String[] str) {
/**
* 需求:幼儿园有两个班 大班: 学习,睡觉 小班: 学习,睡觉 可以将两类事物进行抽取
*/
SmallClass s = new SmallClass();
s.study();
s.sleep();
BigClass b = new BigClass();
b.study();
}
}
/**
* 学生类
*
* @author LGL
*
*/
abstract class Student {
// 学习的内容不一样,抽象
public abstract void study();
// 睡觉
public void sleep() {
System.out.println("躺着睡");
}
}
/**
* 大班
*
* @author LGL
*
*/
class BigClass extends Student {
@Override
public void study() {
System.out.println("学习大班知识");
}
}
/**
* 小班
*
* @author LGL
*
*/
class SmallClass extends Student {
@Override
public void study() {
System.out.println("学习小班知识");
}
@Override
public void sleep() {
System.out.println("卧着睡");
}
}
~~~
> 这个例子输出
![这里写图片描述](http://img.blog.csdn.net/20160528175801355)
> 你拿到一想,是不是根据上面的方法直接复用父类对象的引用?这里我们可以拿到一个单独的类去复用封装
~~~
/**
* 封装工具类
*
* @author LGL
*
*/
class DoStudent {
public void dosome(Student s) {
s.study();
s.sleep();
}
}
~~~
> 这样我们使用
~~~
DoStudent dos = new DoStudent();
dos.dosome(new BigClass());
dos.dosome(new SmallClass());
~~~
> 得到的结果
![这里写图片描述](http://img.blog.csdn.net/20160528180609327)
> 我们再来看下多态的代码特点,我们举个例子
~~~
//公共的 类 类名
public class HelloJJAVA {
// 公共的 静态 无返回值 main方法 数组
public static void main(String[] str) {
zi z = new zi();
z.method1();
z.method2();
z.method3();
}
}
class Fu {
void method1() {
System.out.println("fu method1");
}
void method2() {
System.out.println("fu method2");
}
}
class zi extends Fu {
void method1() {
System.out.println("zi method1");
}
void method3() {
System.out.println("zi method3");
}
}
~~~
> 你能告诉我打印的结果吗?
![这里写图片描述](http://img.blog.csdn.net/20160528181406080)
> 我们现在用多态的思想去做
![这里写图片描述](http://img.blog.csdn.net/20160528181615487)
> 你会知道,3是引用不了的,我现在把报错的的地方注释掉,然后你能告诉我运行的结果吗
![这里写图片描述](http://img.blog.csdn.net/20160528181803092)
> 我们可以总结出特点(在多态中成员函数的特点)
* 在编译时期。参阅引用型变量所属的类是否有调用的方法,如果由,编译通过。如果没有编译失败
* 在运行时期,参阅对象所属的类中是否有调用的方法
* 简单总结就是成员函数在多态调用时,编译看左边,运行看右边
> 我们再在子类和父类中都定义一个int值分别是5和8
>
> 我们这么输出
~~~
Fu f = new zi();
System.out.println(f.num);
zi z = new zi();
System.out.println(z.num);
~~~
> 输出多少呢?
![这里写图片描述](http://img.blog.csdn.net/20160528182536071)
> 这里就总结出
* 在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属)
* 在多态中,静态成员变量的特点:无论编译和运行,都参考左边
> 我们把学到的应用在案例上
~~~
//公共的 类 类名
public class HelloJJAVA {
// 公共的 静态 无返回值 main方法 数组
public static void main(String[] str) {
/**
* 需求:电脑运行实例,电脑运行基于主板
*/
MainBoard b = new MainBoard();
b.run();
}
}
/**
* 主板
*
* @author LGL
*
*/
class MainBoard {
public void run() {
System.out.println("主板运行了");
}
}
~~~
> 我们程序这样写, 无疑看出来很多弊端,我想上网,看电影,他却没有这功能,我们要怎么去做,我们重新设计程序,再增加
~~~
/**
* 网卡
*
* @author LGL
*
*/
class NetCard {
public void open() {
System.out.println("打开网络");
}
public void close() {
System.out.println("关闭网络");
}
}
~~~
> 但是这样,还是主板的耦合性是在是太强了,不适合扩展,所以,这个程序一定不是一个好的程序我,我们重新设计,用一个标准的接口
~~~
import javax.print.attribute.standard.MediaName;
//公共的 类 类名
public class HelloJJAVA {
// 公共的 静态 无返回值 main方法 数组
public static void main(String[] str) {
/**
* 需求:电脑运行实例,电脑运行基于主板
*/
MainBoard m = new MainBoard();
m.run();
// 没有设备,有设备的话之类传进去
m.userPCI(null);
}
}
/**
* 扩展接口
*
* @author LGL
*
*/
interface PCI {
public void open();
public void close();
}
/**
* 主板
*
* @author LGL
*
*/
class MainBoard {
public void run() {
System.out.println("主板运行了");
}
public void userPCI(PCI p) {
if (p != null) {
p.open();
p.close();
} else {
System.out.println("没有设备");
}
}
}
~~~
> 我们现在不管增加听音乐还是上网的功能,只要实现PCI的接口,就可以实现,我们现在增加一个上网功能,该怎么做?
~~~
//公共的 类 类名
public class HelloJJAVA {
// 公共的 静态 无返回值 main方法 数组
public static void main(String[] str) {
/**
* 需求:电脑运行实例,电脑运行基于主板
*/
MainBoard m = new MainBoard();
m.run();
// 没有设备
m.userPCI(null);
// 有设备
m.userPCI(new NetCard());
}
}
/**
* 扩展接口
*
* @author LGL
*
*/
interface PCI {
public void open();
public void close();
}
/**
* 主板
*
* @author LGL
*
*/
class MainBoard {
public void run() {
System.out.println("主板运行了");
}
public void userPCI(PCI p) {
if (p != null) {
p.open();
p.close();
} else {
System.out.println("没有设备");
}
}
}
/**
* 网卡
*
* @author LGL
*
*/
class NetCard implements PCI {
public void open() {
System.out.println("打开网络");
}
public void close() {
System.out.println("关闭网络");
}
}
~~~
> 这样我们运行
![这里写图片描述](http://img.blog.csdn.net/20160528192108605)
> 现在的主板是不是扩展性特别强,这就是多态的扩展性
>
> OK,我们本节的篇幅就先到这里,如果感兴趣的话,可以加群:555974449
版权声明:本文为博主原创文章,博客地址:http://blog.csdn.net/qq_26787115,未经博主允许不得转载。
- 0-发现
- AndroidInterview-Q-A
- Android能让你少走弯路的干货整理
- LearningNotes
- temp
- temp11
- 部分地址
- 0-待办任务
- 待补充列表
- 0-未分类
- AndroidView事件分发与滑动冲突处理
- Spannable
- 事件分发机制详解
- 1-Java
- 1-Java-01基础
- 未归档
- 你应该知道的JDK知识
- 集合框架
- 1-Java-04合集
- Java之旅0
- Java之旅
- JAVA之旅01
- JAVA之旅02
- JAVA之旅03
- JAVA之旅04
- JAVA之旅05
- JAVA之旅06
- JAVA之旅07
- JAVA之旅08
- JAVA之旅09
- java之旅1
- JAVA之旅10
- JAVA之旅11
- JAVA之旅12
- JAVA之旅13
- JAVA之旅14
- JAVA之旅15
- JAVA之旅16
- JAVA之旅17
- JAVA之旅18
- JAVA之旅19
- java之旅2
- JAVA之旅20
- JAVA之旅21
- JAVA之旅22
- JAVA之旅23
- JAVA之旅24
- JAVA之旅25
- JAVA之旅26
- JAVA之旅27
- JAVA之旅28
- JAVA之旅29
- java之旅3
- JAVA之旅30
- JAVA之旅31
- JAVA之旅32
- JAVA之旅33
- JAVA之旅34
- JAVA之旅35
- 1-Java-05辨析
- HashMapArrayMap
- Java8新特性
- Java8接口默认方法
- 图解HashMap(1)
- 图解HashMap(2)
- 2-Android
- 2-Android-1-基础
- View绘制流程
- 事件分发
- AndroidView的事件分发机制和滑动冲突解决
- 自定义View基础
- 1-安卓自定义View基础-坐标系
- 2-安卓自定义View基础-角度弧度
- 3-安卓自定义View基础-颜色
- 自定义View进阶
- 1-安卓自定义View进阶-分类和流程
- 10-安卓自定义View进阶-Matrix详解
- 11-安卓自定义View进阶-MatrixCamera
- 12-安卓自定义View进阶-事件分发机制原理
- 13-安卓自定义View进阶-事件分发机制详解
- 14-安卓自定义View进阶-MotionEvent详解
- 15-安卓自定义View进阶-特殊形状控件事件处理方案
- 16-安卓自定义View进阶-多点触控详解
- 17-安卓自定义View进阶-手势检测GestureDetector
- 2-安卓自定义View进阶-绘制基本图形
- 3-安卓自定义View进阶-画布操作
- 4-安卓自定义View进阶-图片文字
- 5-安卓自定义View进阶-Path基本操作
- 6-安卓自定义View进阶-贝塞尔曲线
- 7-安卓自定义View进阶-Path完结篇伪
- 8-安卓自定义View进阶-Path玩出花样PathMeasure
- 9-安卓自定义View进阶-Matrix原理
- 通用类介绍
- Application
- 2-Android-2-使用
- 2-Android-02控件
- ViewGroup
- ConstraintLayout
- CoordinatorLayout
- 2-Android-03三方使用
- Dagger2
- Dagger2图文完全教程
- Dagger2最清晰的使用教程
- Dagger2让你爱不释手-终结篇
- Dagger2让你爱不释手-重点概念讲解、融合篇
- dagger2让你爱不释手:基础依赖注入框架篇
- 阅读笔记
- Glide
- Google推荐的图片加载库Glide:最新版使用指南(含新特性)
- rxjava
- 这可能是最好的RxJava2.x入门教程完结版
- 这可能是最好的RxJava2.x入门教程(一)
- 这可能是最好的RxJava2.x入门教程(三)
- 这可能是最好的RxJava2.x入门教程(二)
- 这可能是最好的RxJava2.x入门教程(五)
- 这可能是最好的RxJava2.x入门教程(四)
- 2-Android-3-优化
- 优化概况
- 各种优化
- Android端秒开优化
- apk大小优化
- 内存分析
- 混淆
- 2-Android-4-工具
- adb命令
- 一键分析Android的BugReport
- 版本控制
- git
- git章节简述
- 2-Android-5-源码
- HandlerThread 源码分析
- IntentService的使用和源码分析
- 2-Android-9-辨析
- LRU算法
- 什么是Bitmap
- 常见图片压缩方式
- 3-Kotlin
- Kotlin使用笔记1-草稿
- Kotlin使用笔记2
- kotlin特性草稿
- Kotlin草稿-Delegation
- Kotlin草稿-Field
- Kotlin草稿-object
- 4-JavaScript
- 5-Python
- 6-Other
- Git
- Gradle
- Android中ProGuard配置和总结
- gradle使用笔记
- Nexus私服搭建
- 编译提速最佳实践
- 7-设计模式与架构
- 组件化
- 组件化探索(OKR)
- 1-参考列表
- 2-1-组件化概述
- 2-2-gradle配置
- 2-3-代码编写
- 2-4-常见问题
- 2-9-值得一读
- 8-数据结构与算法
- 0临时文件
- 汉诺塔
- 8-数据-1数据结构
- HashMap
- HashMap、Hashtable、HashSet 和 ConcurrentHashMap 的比较
- 迟到一年HashMap解读
- 8-数据-2算法
- 1个就够了
- Java常用排序算法(必须掌握的8大排序算法)
- 常用排序算法总结(性能+代码)
- 必须知道的八大种排序算法(java实现)
- 9-职业
- 阅读
- 书单
- 面试
- 面试-01-java
- Java面试题全集骆昊(上)
- Java面试题全集骆昊(下)
- Java面试题全集骆昊(中)
- 面试-02-android
- 40道Android面试题
- 面试-03-开源源码
- Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程
- 面试-07-设计模式
- 面试-08-算法
- 面试-09-其他
- SUMMARY
- 版权说明
- temp111