# 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();
~~~
> 因為也是動物類型,我們輸出

> 這就是多態在程序中的表現
* 父類的引用指向了自己的子類對象,這就是多態的代碼體現形式,人 = 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();
~~~

> 也就是說,轉型是強制將父類的引用,轉為子類類型,向下轉型。千萬不要將父類對象轉成子類對象,我們能轉換的是父類引用指向子類對象的子類,多態自始至終都是子類對象在做著變化
>
> 那么你會了強轉之后,你就說,我可以這樣做
~~~
//公共的 類 類名
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();
}
}
~~~
> 這樣是不是可以?我們看結果

> 這里報錯了,提示的是狗類型不行轉換成貓類型,的確,不能隨便亂轉。我們價格判斷,怎么判斷呢?條件語句該怎么寫呢?這里我們又有一個關鍵字了**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();
}
}
}
~~~
> 這樣我們加了判斷之后,我們就可以知道

> 既然多態說了這么多,我們來看看多態的應用吧,還是以一個需求開始去分析
~~~
//公共的 類 類名
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("臥著睡");
}
}
~~~
> 這個例子輸出

> 你拿到一想,是不是根據上面的方法直接復用父類對象的引用?這里我們可以拿到一個單獨的類去復用封裝
~~~
/**
* 封裝工具類
*
* @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());
~~~
> 得到的結果

> 我們再來看下多態的代碼特點,我們舉個例子
~~~
//公共的 類 類名
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");
}
}
~~~
> 你能告訴我打印的結果嗎?

> 我們現在用多態的思想去做

> 你會知道,3是引用不了的,我現在把報錯的的地方注釋掉,然后你能告訴我運行的結果嗎

> 我們可以總結出特點(在多態中成員函數的特點)
* 在編譯時期。參閱引用型變量所屬的類是否有調用的方法,如果由,編譯通過。如果沒有編譯失敗
* 在運行時期,參閱對象所屬的類中是否有調用的方法
* 簡單總結就是成員函數在多態調用時,編譯看左邊,運行看右邊
> 我們再在子類和父類中都定義一個int值分別是5和8
>
> 我們這么輸出
~~~
Fu f = new zi();
System.out.println(f.num);
zi z = new zi();
System.out.println(z.num);
~~~
> 輸出多少呢?

> 這里就總結出
* 在多態中,成員變量的特點:無論編譯和運行,都參考左邊(引用型變量所屬)
* 在多態中,靜態成員變量的特點:無論編譯和運行,都參考左邊
> 我們把學到的應用在案例上
~~~
//公共的 類 類名
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("關閉網絡");
}
}
~~~
> 這樣我們運行

> 現在的主板是不是擴展性特別強,這就是多態的擴展性
>
> 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