多態動手動腦

来源:http://www.cnblogs.com/kailugaji/archive/2016/11/19/6081624.html
-Advertisement-
Play Games

一、怎樣判斷對象是否可以轉換?可以使用instanceof運算符判斷一個對象是否可以轉換為指定的類型,參看實例: TestInstanceof.java 二、下列語句哪一個將引起編譯錯誤?為什麼?哪一個會引起運行時錯誤?為什麼? m=d; d=m; d=(Dog)m; d=c; c=(Cat)m; ...


一、怎樣判斷對象是否可以轉換?可以使用instanceof運算符判斷一個對象是否可以轉換為指定的類型,參看實例: TestInstanceof.java

 

public class TestInstanceof
{
    public static void main(String[] args) 
    {
        //聲明hello時使用Object類,則hello的編譯類型是Object,Object是所有類的父類
        //但hello變數的實際類型是String
        Object hello = "Hello";
        //String是Object類的子類,所以返回true。
        System.out.println("字元串是否是Object類的實例:" + (hello instanceof Object));
        //返回true。
        System.out.println("字元串是否是String類的實例:" + (hello instanceof String));
        //返回false。
        System.out.println("字元串是否是Math類的實例:" + (hello instanceof Math));
        //String實現了Comparable介面,所以返回true。
        System.out.println("字元串是否是Comparable介面的實例:" + (hello instanceof Comparable));
        String a = "Hello";
        //String類既不是Math類,也不是Math類的父類,所以下麵代碼編譯無法通過
        //System.out.println("字元串是否是Math類的實例:" + (a instanceof Math));
    }
}

 

二、下列語句哪一個將引起編譯錯誤?為什麼?哪一個會引起運行時錯誤?為什麼?

m=d;

d=m;

d=(Dog)m;

d=c;

c=(Cat)m;

先進行自我判斷,得出結論後,運行TestCast.java實例代碼,看看你的判斷是否正確

 

class Mammal{}
class Dog extends Mammal {}
class Cat extends Mammal{}

public class TestCast
{
    public static void main(String args[])
    {
        Mammal m;
        Dog d=new Dog();
        Cat c=new Cat();
        m=d;
        //d=m;
        d=(Dog)m;
        //d=c;
        //c=(Cat)m;

    }
}

 

d=m;

d=c;

c=(Cat)m;

這三句話有錯。

三、請看以下“變態”的類(參看示例ParentChildTest.java),運行以下測試代碼,並回答問題:1.程式運行結果是什麼?2.你如何解釋會得到這樣的輸出?3.電腦是不會出錯的,之所以得到這樣的運行結果也是有原因的,那麼從這些運行結果中,你能總結出Java的哪些語法特性?

 

public class ParentChildTest {
    public static void main(String[] args) {
        Parent parent=new Parent();
        parent.printValue();
        Child child=new Child();
        child.printValue();
        
        parent=child;
        parent.printValue();
        
        parent.myValue++;
        parent.printValue();
        
        ((Child)parent).myValue++;
        parent.printValue();
        
    }
}

class Parent{
    public int myValue=100;
    public void printValue() {
        System.out.println("Parent.printValue(),myValue="+myValue);
    }
}
class Child extends Parent{
    public int myValue=200;
    public void printValue() {
        System.out.println("Child.printValue(),myValue="+myValue);
    }
}

 

1、結果:

2、Java語法特性:

    1)當子類與父類擁有一樣的方法,並且讓一個父類變數引用一個子類對象時,到底調用哪個方法,由對象自己的“真實”類型所決定,這就是說:對象是子類型的,它就調用子類型的方法,是父類型的,它就調用父類型的方法。

這個特性實際上就是面向對象“多態”特性的具體表現。

    2)如果子類與父類有相同的欄位,則子類中的欄位會代替或隱藏父類的欄位,子類方法中訪問的是子類中的欄位(而不是父類中的欄位)。如果子類方法確實想訪問父類中被隱藏的同名欄位,可以用super關鍵字來訪問它。如果子類被當作父類使用,則通過子類訪問的欄位是父類的!

四、請使用javap查看編譯器為TestPolymorphism.java生成的位元組碼指令,然後通過互聯網搜索資料,嘗試從底層開始理解Java編譯器是如何為多態代碼生成位元組碼指令,在程式運行過程中,多態特性又是如何實現的。

 

class Parent1        
{
    public int value=100;    
    public void Introduce()
    {
            System.out.println("I'm father");
        }
}
class Son extends Parent1
{
    public int value=101;
         public void Introduce()
    {
            System.out.println("I'm son");    
}
}
class Daughter extends Parent1
{
    public int value=102;
    public void Introduce()
    {
            System.out.println("I'm daughter");    
}
}
public class TestPolymorphism
{
    public static void main(String args[])
    {
        Parent1 p=new Parent1();
        p.Introduce();//子類的方法
        System.out.println(p.value);//父類的變數對象
        p=new Son();
        p.Introduce();
        System.out.println(p.value);
        p=new Daughter();
        p.Introduce();
        System.out.println(p.value);
    }
}

結果:

五、在實例中理解多態的含義與用途

1、三種動物對應三個類,每個類定義一個eat()方法,表示吃飼養員給它們的食物,再設計一個Feeder類代表飼養員,其name欄位保存飼養員名字,三個方法分別代表喂養三種不同的動物,其參數分別引用三種動物對象。

 

package Zoo1;
public class Zoo 
{
    public static void main(String args[])
    {
        Feeder f = new Feeder("小李");
        // 飼養員小李喂養一隻獅子
        f.feedLion(new Lion());
        // 飼養員小李喂養十隻猴子
        for (int i = 0; i < 10; i++)
         {
            f.feedMonkey(new Monkey());
        }        
        // 飼養員小李喂養5只鴿子
        for (int i = 0; i < 5; i++)
         {
            f.feedPigeon(new Pigeon());
        }    
    }
}
class Feeder 
{
    public String name;
    public Feeder(String name)
    {
        this.name = name;
    }    
    public void feedLion(Lion l)
    {
        l.eat();
    }    
    public void feedPigeon(Pigeon p)
    {
        p.eat();
    }    
    public void feedMonkey(Monkey m)
    {
        m.eat();
    }
}
class Lion
{
    public void eat() 
    {
        System.out.println("我不吃肉誰敢吃肉!");
    }
}
class Monkey 
{
    public void eat() 
    {
        System.out.println("我什麼都吃,尤其喜歡香蕉。");
    }
}
class Pigeon 
{
    public void eat() 
    {
        System.out.println("我要減肥,所以每天只吃一點大米。");
    }
}

 

2、第一次程式重構:引入繼承,簡化Feeder

 

package Zoo2;
public class Zoo 
{   
    public static void main(String args[])
    {
            Feeder f = new Feeder("小李");
            //飼養員小李喂養一隻獅子
            f.feedAnimal(new Lion());
            //飼養員小李喂養十隻猴子
            for (int i = 0; i < 10; i++) 
        {
                f.feedAnimal(new Monkey());    
        }
            //飼養員小李喂養5只鴿子
            for (int i = 0; i < 5; i++) 
        {
                f.feedAnimal(new Pigeon());
            }
    }
}
class Feeder 
{
    public String name;
    Feeder(String name) 
    {
        this.name = name;
    }    
    public void feedAnimal(Animal an) 
   {
        an.eat();
    }
}
abstract class Animal 
{
    public abstract void eat();
}
class Lion extends Animal 
{
    public void eat() 
   {
        System.out.println("我不吃肉誰敢吃肉!");
    }
}
class Monkey extends Animal 
{
    public void eat() 
    {
        System.out.println("我什麼都吃,尤其喜歡香蕉。");
    }
}
class Pigeon extends Animal 
{    
   public void eat() 
    {
       System.out.println("我要減肥,所以每天只吃一點大米。");
    }
}

 

3、第二次程式重構,修改feedAnimals方法,讓它接收一個Animal數組……

 

package Zoo3;
public class Zoo {
    public static void main(String args[]) {
        Feeder f = new Feeder("小李");
        Animal[] ans = new Animal[16];
        //飼養員小李喂養一隻獅子
        ans[0] = new Lion();
        //飼養員小李喂養十隻猴子
        for (int i = 0; i < 10; i++) {
            ans[1 + i] = new Monkey();
        }
        //飼養員小李喂養5只鴿子
        for (int i = 0; i < 5; i++) {
            ans[11 + i] = new Pigeon();
        }
        f.feedAnimals(ans);
    }
}
class Feeder {
    public String name;
    Feeder(String name) {
        this.name = name;
    }
    public void feedAnimals(Animal[] ans) {
        for (Animal an : ans) {
            an.eat();
        }
    }
}
abstract class Animal {
    public abstract void eat();
}
class Lion extends Animal {
    public void eat() {
        System.out.println("我不吃肉誰敢吃肉!");
    }
}
class Monkey extends Animal {
    public void eat() {
        System.out.println("我什麼都吃,尤其喜歡香蕉。");
    }
}
class Pigeon extends Animal {
    public void eat() {
        System.out.println("我要減肥,所以每天只吃一點大米。");
    }
}

 

4、第三次重構,修改feedAnimals方法,讓其接收一個元素數目可變的對象容器。

 

package Zoo4;
import java.util.Vector;
public class Zoo {
    public static void main(String args[]) {
        Feeder f = new Feeder("小李");
        Vector<Animal> ans = new Vector<Animal>();
        //飼養員小李喂養一隻獅子
        ans.add(new Lion());
        //飼養員小李喂養十隻猴子
        for (int i = 0; i < 10; i++) {
            ans.add(new Monkey());
        }
        //飼養員小李喂養5只鴿子
        for (int i = 0; i < 5; i++) {
            ans.add(new Pigeon());
        }
        f.feedAnimals(ans);
    }
}
class Feeder {
    public String name;
    Feeder(String name) {
        this.name = name;
    }
    public void feedAnimals(Vector<Animal> ans) {
        for (Animal an : ans) {
            an.eat();
        }
    }
}
abstract class Animal {
    public abstract void eat();
}
class Lion extends Animal {
    public void eat() {
        System.out.println("我不吃肉誰敢吃肉!");
    }
}
class Monkey extends Animal {
    public void eat() {
        System.out.println("我什麼都吃,尤其喜歡香蕉。");
    }
}
class Pigeon extends Animal {
    public void eat() {
        System.out.println("我要減肥,所以每天只吃一點大米。");
    }
}

 

5、從這個示例中可以看到,通過在編程中應用多態,可以使我們的代碼具有更強的適用性。當需求變化時,多態特性可以幫助我們將需要改動的地方減少到最低限度。

多態編程有兩種主要形式:

1)繼承多態:示常式序使用的方法

2)介面多態:使用介面代替抽象基類。

使用多態最大的好處是:

當你要修改程式並擴充系統時,你需要修改的地方較少,對其它部分代碼的影響較小!千萬不要小看這兩個“較”字!程式規模越大,其優勢就越突出。

六、用多態的方法模擬ATM操作流程。

 

//王榮榮 2016/11/18
import java.util.Scanner;
class PersonalAccount{
    private String passWord="123456";//密碼
    private String number;//銀行卡號
    private int money=0;
    public int getMoney(){
        return money;
        }//餘額
    public void setPw(String s){
        passWord=s;
        }//設置密碼
    public void addMoney(int x){
        money+=x;
        }//加錢
    public void minusMoney(int x){
        money-=x;
        }//減錢
    public boolean whetherPwTrue(String s){//密碼是否正確
        if(s.equals(passWord))
            return true;
        else return false;
    }
    }
    abstract class PATM{
    abstract boolean withdraw(int x);//取款
    abstract void save(int x);//存款
    abstract boolean transfer(String s,int x);//轉賬
    abstract boolean ifPass(String s);//判斷輸入的密碼是否正確
    abstract int getRest();//查詢餘額
    abstract void setPassword(String s);//設置密碼
    }
    class ATM extends PATM{
    private String numbers[]={"123451","123452",
            "123453","123454","123455"};//資料庫中已有的賬戶卡號
    private PersonalAccount account=new PersonalAccount();
    public boolean withdraw(int x) {
        if(x>account.getMoney())
            return false;
        else{
            account.minusMoney(x);
            return true;
        }
    }
    public void save(int x) {
        account.addMoney(x);
    }
    public boolean transfer(String s, int x) {
        //轉賬
        //先判斷轉到賬戶號是否存在
        //再判斷餘額是否足夠
        boolean flag=false;
        for(int i=0;i<numbers.length;i++)
            if(s.equals(numbers[i])) flag=true;
        if(x>account.getMoney()) flag=false;
        if(x<=account.getMoney()&&flag) account.minusMoney(x);;
        return flag;
    }
    public boolean ifPass(String s) {
        return account.whetherPwTrue(s);
    }
    public int getRest() {
        return account.getMoney();
    }
    public void setPassword(String s) {
        account.setPw(s);        
    }
    }
public class Atm1 {
    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        ATM atm=new ATM();
        int choose=0,num=0;
        String pw="";
        next:while(true){
            System.out.println("是否進入賬戶(0否1是):");
            int kk=in.nextInt();
            if(kk==0) break;
            else if(kk!=1){
                System.out.println("輸入錯誤!");
                continue;
            }
            System.out.println("輸入賬戶密碼:");
            pw=in.next();
            if(atm.ifPass(pw)){
                while(true){
                    showFace();
                    choose=in.nextInt();
                    switch(choose){
                    case 1:
                        System.out.println("輸入存款金額:");
                        num=in.nextInt();
                        atm.save(num);
                        System.out.println("存款成功!");
                        System.out.println("當前餘額:"+atm.getRest()+"元");
                        break;
                    case 2:
                        System.out.println("請選擇:");
                        int a[]={100,500,1000,1500,2000,5000};
                        for(int i=0;i<a.length;i++)
                            System.out.println((i+1)+"."+a[i]+"元");
                        System.out.println("7.其他");
                        int ch=in.nextInt();
                        if(ch>=1&&ch<=6){
                            if(atm.withdraw(a[ch-1]))
                                System.out.println("取款成功!");
                            else
                                System.out.println("餘額不足!");
                        }
                        else if(ch==7){
                            System.out.println("請輸入取款金額:");
                            num=in.nextInt();
                            if(atm.withdraw(num))
                                System.out.println("取款成功!");
                            else 
                                System.out.println("餘額不足!");
                        }
                        else 
                            System.out.println("輸入有誤!");
                        System.out.println("當前餘額:"+atm.getRest()+"元");
                        break;
                    case 3:
                        System.out.println("賬戶號:");
                        String s=in.next();
                        System.out.println("轉賬金額:");
                        int i=in.nextInt();
                        if(atm.transfer(s, i))
                            System.out.println("轉賬成功!");
                        else
                            System.out.println("轉賬失敗!");
                        System.out.println("當前餘額:"+atm.getRest()+"元");
                        break;
                    case 4:
                        System.out.println("輸入六位數密碼:");
                        String p=in.next();
                        atm.setPassword(p);
                        break;
                    case 5:
                        System.out.println("當前餘額:"+atm.getRest()+"元");
                        break;
                    default:
                        continue next;
                    }
                }
            }
            else
                System.out.println("密碼錯誤!");
        }
    }
  //顯示菜單方法
    public static void showFace(){
        System.out.println("1.存款");
        System.out.println("2.取款");
        System.out.println("3.轉賬匯款");
        System.out.println("4.修改密碼");
        System.out.println("5.查詢餘額");
        System.out.println("6.退卡");
        System.out.println("請選擇:");
    }
    }

 

結果:

 

 

 

 

 

 

 

 


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

-Advertisement-
Play Games
更多相關文章
  • Hi,大家好!我是CrazyCatJack,你們可以叫我CCJ或者瘋貓。今天我給大家帶來的是u-boot的源代碼彙編段分析,以後還會給大家講解後續的C代碼,請持續關註哦^_^ 先簡單說一下u-boot,在嵌入式開發中,u-boot起著至關重要的作用:讀出嵌入式系統內核並啟動內核。因此非常有必要對u- ...
  • 本人菜鳥一枚,大學里憑興趣學了一點WP的皮毛,後來又幸運(或者不幸)的進了一家專註於Windows生態的公司做了一段時間的UWP。在博客園寫點自己遇到的東西,作為分享,也作為自己的備忘,如果有錯誤的地方,或者可以提升B格的地方,希望園子里的大神們不吝賜教。 初進公司時,公司要做支付相關的業務,需要和 ...
  • #! usr/bin/env python#!-*-conding:utf-8-*-#第一步:定義變數 name = 'python' passwd = 'password'#第二步:寫while迴圈 定義count=0#第三步:判斷count=3則列印print("Account Be Locke ...
  • 分散式系統關鍵點 分散式系統(distributed system)是建立在網路之上的軟體系統。正是因為軟體的特性,所以分散式系統具有高度的內聚性和透明性。因此,網路和分散式系統之間的區別更多的在於高層軟體(特別是操作系統),而不是硬體。內聚性是指每一個資料庫分佈節點高度自治,有本地的資料庫管理系統 ...
  • 轉載:http://www.jb51.net/article/40193.htm JS里設定延時: 使用SetInterval和設定延時函數setTimeout 很類似。setTimeout 運用在延遲一段時間,再進行某項操作。 setTimeout("function",time) 設置一個超時對 ...
  • 分組後,統計記錄條數: SELECT num,count(*) AS counts from test_a GROUP BY num; 查詢結果如下: 對num去重後的數量的統計: SELECT count(t.counts) FROM ( SELECT num,count(*) AS counts ...
  • 協議與相容性 spider使用java語言開發,使用Spring作為IoC容器,採用TCP/IP協議,在此基礎上,結合SaaS系統模式的特性進行針對性和重點設計,以更加靈活和高效的滿足多租戶系統、高可用、分散式部署的要求。 採用JSON作為序列化機制,後續版本可能會考慮支持protobuf(java ...
  • 1、局部變數 運行結果: 0 1 2 3 4 4 i是for語句裡面的局部變數。但在python裡面,在同一方法體內,定義了一個局部變數,該變數的作用域是定義行開始至該方法體結束。 在其他編程語言,“print i”那一句是有誤的,因為i沒有定義 例1: 結果: True 例2: 最後一行有誤,因為 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...