Java學習 (十三)、面向對象編程(五)多態--對象上下轉型,動態綁定和靜態綁定,應用

来源:http://www.cnblogs.com/wzy330782/archive/2016/03/17/5289744.html
-Advertisement-
Play Games

多態 概念:指同一操作作用於某一類對象,可以有不同的解釋,產生不同的執行結果; 存在的必要條件 ① 需要存在繼承和實現關係; ② 同樣的方法調用而執行不同操作,運行不同代碼(重寫操作); ③ 在運行時父類或者介面的引用變數可以引用其子類的對象; 作用 ① 多態通過分離做什麼和怎麼做,從另一個角度將接


多態

概念:指同一操作作用於某一類對象,可以有不同的解釋,產生不同的執行結果;

存在的必要條件

①   需要存在繼承和實現關係;

②   同樣的方法調用而執行不同操作,運行不同代碼(重寫操作);

③   在運行時父類或者介面的引用變數可以引用其子類的對象;

作用

①   多態通過分離做什麼和怎麼做,從另一個角度將介面和實現進行分離;

②   “多態”則消除了類型之間耳朵耦合關係;

③   多態的存在提高了程式的擴展和後期的可維護性;

 1 public class AnimalDemo{
 2     public static void main(String []args){
 3         //父類的引用變數可以引用其子類對象
 4         Animal animal1=new Dog("旺財");
 5         animal1.eat();
 6         
 7         Animal animal2=new Cat("招財");
 8         animal2.eat();
 9         
10     }
11 }
12 
13 class Animal{
14     private String name;
15     public Animal(String name){
16         this.name=name;
17     }
18     
19     //這是一個通用的方法,實現沒有太大的意義
20     //只是告訴其子類去實現它
21     public void eat(){
22         
23     }
24 }
25 
26 class Dog extends Animal{
27     public Dog(String name){
28         super(name);
29     }
30     
31     //對父類的方法進行重寫
32     public void eat(){
33         System.out.println("啃骨頭");
34     }
35 }
36 
37 class Cat extends Animal{
38     public Cat(String name){
39         super(name);
40     }
41     
42     //對父類的方法進行重寫
43     public void eat(){
44         System.out.println("吃魚");
45     }
46 }
View Code

對象上下轉型

①   由子類轉型成父類,在繼承圖上是向上移動的,一般稱為向上轉型;

②   向上轉型是從一個較專用類型像較通用類型轉型,所以總是安全的,也就是說,子類是父類的一個超集;

③   向上轉型過程中,類介面中唯一可能發生的事情就是丟失方法,而不是獲取方法;

④   與之相反的操作是向下轉型,不安全(可能需要instanceof操作符協助);

⑤   LSP(liskov替換原則):子類型必須能夠替換掉它們的基類型;

⑥   安全的上轉和LSP的實施,充分體現繼承的“is-a”關係;

 

上面的demo就是向上轉型

 1 public class AnimalDemo{
 2     public static void main(String []args){
 3         //父類的引用變數可以引用其子類對象
 4         Animal animal1=new Dog("旺財狗");//向上轉型
 5         //向上轉型首先是安全的,但可能會導致子類方法的丟失
 6         //父類的引用變數只能調用父類中有的方法,或子類中重寫的方法
 7         animal1.eat();
 8         //animal1.sleep();//在dog中的特有方法不能使用
 9         
10         Animal animal2=new Cat("招財貓");
11         animal2.eat();
12         
13         
14         //向下轉型是不安全的
15          //Cat cat=(Cat)animal1;//轉換異常
16         
17     }
18 }
19 
20 class Animal{
21     private String name;
22     public Animal(String name){
23         this.name=name;
24     }
25     
26     //這是一個通用的方法,實現沒有太大的意義
27     //只是告訴其子類去實現它
28     public void eat(){
29         
30     }
31 }
32 
33 class Dog extends Animal{
34     public Dog(String name){
35         super(name);
36     }
37     
38     //對父類的方法進行重寫
39     public void eat(){
40         System.out.println("啃骨頭");
41     }
42     
43     public void sleep(){
44         System.out.println("睡覺");
45     }
46 }
47 
48 class Cat extends Animal{
49     public Cat(String name){
50         super(name);
51     }
52     
53     //對父類的方法進行重寫
54     public void eat(){
55         System.out.println("吃魚");
56     }
57 }
View Code

instanceof運算符用來在運行時通過返回一個布爾值來指出對象是否是特定類或者是它的子類的一個實例;

用法:

         result=object instanceof calss

         result:布爾類型

         object:必選項,任意對象表達式

         class:必選項,任意已定義的對象類

說明:如果object是class或者其子類的一個實例,則instanceof運算符返回true,如果不是或者object是null,則返回false;

典型使用場合:在對對象做下轉型之前,沒有其它有關對象類型信息時務必使用instanceof來判斷一下,以免拋出ClassCastException異常;

 1 public class AnimalDemo{
 2     public static void main(String []args){
 3         //父類的引用變數可以引用其子類對象
 4         Animal animal1=new Dog("旺財狗");//向上轉型
 5         //向上轉型首先是安全的,但可能會導致子類方法的丟失
 6         //父類的引用變數只能調用父類中有的方法,或子類中重寫的方法
 7         animal1.eat();
 8         //animal1.sleep();//在dog中的特有方法不能使用
 9         
10         Animal animal2=new Cat("招財貓");
11         animal2.eat();
12         
13         
14         //向下轉型是不安全的
15          //Cat cat=(Cat)animal1;//轉換異常
16          
17          //解決方法
18          if(animal1 instanceof Cat){
19              //未進入
20              System.out.println("進入執行");
21              Cat cat=(Cat)animal1;
22          }
23          
24           if(animal2 instanceof Cat){
25              //進入
26              System.out.println("進入執行2");
27              Cat cat=(Cat)animal2;
28              cat.sleep();
29          }
30         
31     }
32 }
33 
34 class Animal{
35     private String name;
36     public Animal(String name){
37         this.name=name;
38     }
39     
40     //這是一個通用的方法,實現沒有太大的意義
41     //只是告訴其子類去實現它
42     public void eat(){
43         
44     }
45 }
46 
47 class Dog extends Animal{
48     public Dog(String name){
49         super(name);
50     }
51     
52     //對父類的方法進行重寫
53     public void eat(){
54         System.out.println("啃骨頭");
55     }
56     
57     public void sleep(){
58         System.out.println("睡覺");
59     }
60 }
61 
62 class Cat extends Animal{
63     public Cat(String name){
64         super(name);
65     }
66     
67     //對父類的方法進行重寫
68     public void eat(){
69         System.out.println("吃魚");
70     }
71     
72     public void sleep(){
73         System.out.println("睡覺");
74     }
75 }
View Code

動態綁定和靜態綁定

概念:

①   在程式執行前方法以及被綁定,針對Java簡單的可以理解為程式編譯期的綁定(靜態綁定)java當中的方法是final,static,private和構造方法都是前期綁定的;

②   運行時,根據變數實際引用的對象類型決定調用哪個方法(動態綁定);

靜態綁定在編譯期進行

         Person.sayHi();

動態綁定在運行期進行

         Person p=new Teacher();

         p.sayHi();

多態的概念基於對象引用的動態綁定特性;

 

多態應用

簡單來說,多態是具有表現多種行為能力的特征;

同一個實現介面,使用不同的實例而執行不同操作;

 

不使用多態:

 1 public class PrinterDemo{
 2     public static void main(String []args){
 3         ColorPrinter cp=new ColorPrinter("惠普");
 4         BlackPrinter bp=new BlackPrinter("戴爾");
 5         School school=new School();
 6         //school.setColorPrinter(cp);
 7         school.setBlackPrinter(bp);//新建的黑白列印時,要修改學習的列印方法
 8         school.print("hello java");
 9         
10         /*以上每次調用不同的子類時特別麻煩,會影響到其他類中的代碼修改*/
11     }
12 }
13 
14 class Printer{
15     private String brand;
16     
17     public Printer(String brand){
18         this.brand=brand;
19     }
20     
21     public String getBrand()
22     {
23         return brand;
24     }
25     
26     //列印方法應該由其子類來具體的實現
27     public void print(String content){
28         
29     }
30 }
31 
32 
33 //開原原則:對修改是封閉的,對擴展是開放的
34 //可以使用多態解決這個問題,父類的引用變數可以引用其子類的對象
35 class School{
36     private ColorPrinter cp=null;
37     private BlackPrinter bp=null;
38     private ZhenPrinter bp=null;
39     
40     //安裝彩色印表機
41     public void setColorPrinter(ColorPrinter cp){
42         this.cp=cp;
43     }    
44     
45     //安裝黑白印表機
46     public void setBlackPrinter(BlackPrinter bp){
47         this.bp=bp;
48     }
49     
50     //安裝針式印表機
51     public void setZhenPrinter(ZhenPrinter bp){
52         this.bp=bp;
53     }
54     
55     public void print(String content){
56         //交給中心所安裝的彩色印表機來列印
57         //cp.print(content);
58         //交給中心所安裝的黑白印表機來列印
59         bp.print(content);
60     }
61     
62 }
63 
64 class ColorPrinter extends Printer{
65     public ColorPrinter(String brand){
66         super(brand);
67     }
68     //對父類的方法進行重寫
69     public void print(String content){
70         System.out.println(getBrand()+"彩色列印:"+content);
71     }
72 }
73 
74 class BlackPrinter extends Printer{
75     public BlackPrinter(String brand){
76         super(brand);
77     }
78     //對父類的方法進行重寫
79     public void print(String content){
80         System.out.println(getBrand()+"黑白列印:"+content);
81     }
82 }
83 
84 class ZhenPrinter extends Printer{
85     public ZhenPrinter(String brand){
86         super(brand);
87     }
88     //對父類的方法進行重寫
89     public void print(String content){
90         System.out.println(getBrand()+"針式列印:"+content);
91     }
92 }
View Code

使用多態:

 1 public class PrinterDemo{
 2     public static void main(String []args){
 3         ColorPrinter cp=new ColorPrinter("惠普");
 4         BlackPrinter bp=new BlackPrinter("戴爾");
 5         ZhenPrinter zp=new ZhenPrinter("戴爾");
 6         School school=new School();
 7         
 8         school.setPrinter(zp);//這裡的參數可以調用較靈活,使用cp,bp,zp都可以,而不用改school類中的方法
 9         school.print("hello java");
10 
11     }
12 }
13 
14 class Printer{
15     private String brand;
16     
17     public Printer(String brand){
18         this.brand=brand;
19     }
20     
21     public String getBrand()
22     {
23         return brand;
24     }
25     
26     //列印方法應該由其子類來具體的實現
27     public void print(String content){
28         
29     }
30 }
31 
32 
33 //開原原則:對修改是封閉的,對擴展是開放的
34 //可以使用多態解決這個問題,父類的引用變數可以引用其子類的對象
35 class School{
36     private Printer p=null;//安裝印表機
37     
38     //拿父類的引用變數作為參數,好處就是可以接受任何其子類的對象
39     //越是抽象的東西就是越穩定的
40     public void setPrinter(Printer p){
41         this.p=p;
42     }
43     
44     public void print(String content){
45         //交給中心所安裝的印表機來列印
46         p.print(content);
47     }
48 }
49 
50 class ColorPrinter extends Printer{
51     public ColorPrinter(String brand){
52         super(brand);
53     }
54     //對父類的方法進行重寫
55     public void print(String content){
56         System.out.println(getBrand()+"彩色列印:"+content);
57     }
58 }
59 
60 class BlackPrinter extends Printer{
61     public BlackPrinter(String brand){
62         super(brand);
63     }
64     //對父類的方法進行重寫
65     public void print(String content){
66         System.out.println(getBrand()+"黑白列印:"+content);
67     }
68 }
69 
70 class ZhenPrinter extends Printer{
71     public ZhenPrinter(String brand){
72         super(brand);
73     }
74     //對父類的方法進行重寫
75     public void print(String content){
76         System.out.println(getBrand()+"針式列印:"+content);
77     }
78 }
View Code

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文主要介紹 Java 泛型的概念和定義,以及 Java 泛型機制的實現原理。 使用泛型程式設計,可以避免隨處可見的 Object 以及強制轉換,提高了代碼的安全性和可讀性。 類型參數(type parameters): Java 和C++一樣,通過引入類型參數進行泛型編程。 泛型類(generic
  • 在前面的討論里我們提到自由數據結構就是產生某種類型的最簡化結構,比如:free monoid, free monad, free category等等。我們也證明瞭List[A]是個free monoid。我們再看看free monad結構Free的定義:scalaz/Free.scala 我們在上
  • 本篇分為兩部分: 一、Swift中的方法嵌套 二、Swift中的命名空間 在 swift 中我們可以讓方法嵌套方法,如: 我們之前在使用 OC 開發時,它是沒有命名空間的,所有的代碼和引用的靜態庫最終都會被編譯到同一個域和二進位中,這樣的後果是一旦我們有重覆的類名的話,就會導致編譯時的衝突和失敗。為
  • 表達式樹: 葉子是操作數,其餘結點為操作符,是二叉樹的其中一種應用 我是分割線 一棵表達式樹如下圖: 若是對它做中序遍歷,則可以得到中綴表達式 做後序遍歷,則可以得到尾碼表達式 已知樹的結點可以表示成: 用尾碼表達式構建一棵表達式樹: 思路:(與尾碼表達式計算四則運算結構相似) 1. 一一讀入輸入字
  • & 160;& 160;& 160;& 160; "上一篇隨筆" 介紹瞭如何使用Gradle內建任務,介紹了自定義Gradle任務類的三種方法(build文件,buildSrc文件夾、新建groovy項目),一個任務是一個原子操作,即不可分割的。項目開發過程中,我們往往需要按照一定順序執行多個任務以
  • 引用:http://jzinfo.javaeye.com/blog/519470 Java的"對象序列化"能讓你將一個實現了Serializable介面的對象轉換成一組byte,這樣日後要用這個對象時候,你就能把這些byte數據恢復出來,並據此重新構建那個對象了。這一點甚至在跨網路的環境下也是如此,...
  • 定義:Threading用於提供線程相關的操作,線程是應用程式中工作的最小單元。 上述代碼創建了10個“前臺”線程,然後控制器就交給了CPU,CPU根據指定演算法進行調度,分片執行指令。 更多方法: 線程鎖 由於線程之間是進行隨機調度,並且每個線程可能只執行n條執行之後,CPU接著執行其他線程。所以,
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...