如何理解Java向下轉型?

  其實向上轉型和向下轉型都是很重要的,可能我們平時見向上轉型多一點,向上轉型也比較好理解。 但是向下轉型,會不會覺得很傻,我是要用子類實例對象,先是生成子類實例賦值給父類引用,在將父類引用向下強轉給子類引用,這不是多此一舉嗎?我不向上轉型也不向下轉型,直接用子類實例就行了。 我開始學習Java時也是這麼想的,這誤區導致我覺得向下轉型就是沒用的。
  隨着技術的提升,我在看開源的項目學習,發現很多地方都用了向下轉型的技術,這就讓我重視了起來,想要重新來複習(學習)這個知識點。也是搜索了許多博客文章,但都沒具體說明向下轉型,只是給了例子演示怎麼使用,反而是向上轉型講了一堆(可能是我沒找到)。
  這篇博客就是講向下轉型的,那我們就來學習下向下轉型,瞭解下這種特性的意義和使用場景

新建一個電子產品接口,如下:

public interface Electronics{

}

很簡單,什麼方法都沒有。
新建一個Thinkpad筆記本類,並實現電子產品接口

public class Thinkpad implements Electronics{

    //Thinkpad引導方法
    public void boot(){
        System.out.println("welcome,I am Thinkpad");        
    }

    //使用Thinkpad編程  
    public void program(){
        System.out.println("using Thinkpad program");
    }

}

新建一個Mouse鼠標類,並實現電子產品接口:

public class Mouse implements Electronics{

    //鼠標移動
    public void move(){
        System.out.println("move the mouse");       
    }

    //鼠標點擊  
    public void onClick(){
        System.out.println("a click of the mouse");
    }

}

新建一個Keyboard鍵盤類,並實現電子產品接口:

public class Keyboard implements Electronics{

    //使用鍵盤輸入    
    public void input(){
        System.out.println("using Keyboard input");
    }

}

這裏子類比較多,是爲了更好的理解。每個類的方法的邏輯實現也很簡單。打印了一行信息

  接下來,我們想象一個情景:我們去商城買電子產品,電子產品很多吧,比如筆記本電腦,鼠標,鍵盤,步步高點讀機哪裏不會點哪裏,我們用的手機,等等,這些都屬於電子產品。電子產品是抽象的。好,那麼我們決定買一臺Thinkpad,一個鼠標和一個鍵盤。
  這時,我們需要一個購物車來裝這些電子產品吧。我們可以添加進購物車,然後通過購物車還能知道存放的電子產品數量,能拿到對應的電子產品。
  那麼,一個購物車類就出來了,如下:

import java.util.ArrayList;
import java.util.List;

public class ShopCar{

    private List<Electronics> mlist = new ArrayList<Electronics>();

    public void add(Electronics electronics){

        mlist.add(electronics);

    }

    public int getSize(){

        return mlist.size();
    }


    public Electronics getListItem(int position){

        return mlist.get(position);

    }


}

  List 集合是用來存放電子產品的,add 方法用來添加電子產品到購物車,getSize 方法用來獲取存放的電子產品數量,getListItem 方法用來獲取相應的電子產品。

  可以看到 List<Electronics> 用了泛型的知識,至於爲什麼要用泛型?這個不做介紹了,泛型很重要的。
而我覺得比較疑惑的是爲什麼是放 Electronics 的泛型,而不是放Thinkpad,Mouse,Keyboard,Phone等?
  如果是List<Thinkpad>,肯定是放不進鼠標Mouse的吧,難道要生成3個集合?這裏是定義了3個電子產品類,但是我如果有100種電子產品呢,要定義100個集合?
  這太可怕了。所以之前,我們寫了一個Electronics接口,提供了一個Electronics的標準,然後讓每一個Electronics子類都去實現這個接口。

  實際上這裏又涉及到了向上轉型的知識點,我們雖然在add 方法將子類實例傳了進來存放,但子類實例在傳進去的過程中也進行了向上轉型
  所以,此時購物車裏存放的子類實例對象,由於向上轉型成Electronics,已經丟失了子類獨有的方法,以上述例子來分析,Thinkpad實例就是丟失了boot() 和program() 這兩個方法,而Mouse實例就是丟失了move()和onClick()這兩個方法

  但是實際使用Thinkpad或Mouse或Keyboard時,這種情況肯定不是我們想要的

接着我們寫一個測試類 Test 去測試購物車裏的電子產品。

測試類 Test 如下:

public class Test{

    public static final int THINKPAD = 0;
    public static final int MOUSE = 1;
    public static final int KEYBOARD = 2;

    public static void main(String[] args){

        //添加進購物車
        ShopCar shopcar = new ShopCar();
        shopcar.add(new Thinkpad());
        shopcar.add(new Mouse());
        shopcar.add(new Keyboard());

        //獲取大小
        System.out.println("購物車存放的電子產品數量爲 ——> "+shopcar.getSize());


        //開始測試thinkpad電腦
        Thinkpad thinkpad = (Thinkpad)shopcar.getListItem(THINKPAD);
        thinkpad.boot();
        thinkpad.program();

        System.out.println("-------------------");

        //開始測試Mouse鼠標
        Mouse mouse = (Mouse)shopcar.getListItem(MOUSE);
        mouse.move();
        mouse.onClick();

        System.out.println("-------------------");

        //開始測試Keyboard鍵盤
        Keyboard keyboard = (Keyboard)shopcar.getListItem(KEYBOARD);
        keyboard.input();
    }

}

運行截圖:

這裏寫圖片描述

舉個例子分析就好

//開始測試thinkpad電腦
Thinkpad thinkpad = (Thinkpad)shopcar.getListItem(THINKPAD);
thinkpad.boot();
thinkpad.program();

shopcar.getListItem(THINKPAD)這句代碼是獲取到Electronics類型的實例。不是Thinkpad的實例

通過向下轉型,賦值給子類引用

Thinkpad thinkpad = (Thinkpad)shopcar.getListItem(THINKPAD);

這樣子類實例又重新獲得了因爲向上轉型而丟失的方法(boot 和program)

   總結一下吧,很多時候,我們需要把很多種類的實例對象,全部扔到一個集合。(這句話很重要)
在這個例子裏就是把Thinkpad筆記本,Mouse鼠標,KeyBoard鍵盤等實例對象,全部扔到一個Shopcar購物車集合。
   但是肯定不可能給他們每個種類都用一個獨立的集合去存放吧,這個時候我們應該尋找到一個標準,接口就是一個標準。這些都是各種電子產品,抽象成電子產品。然後一個Electronics接口就出來了。
   再回到剛纔,我們把很多種類的實例對象全部扔到一個集合。或許這樣比較好理解:把很多種類的子類實例對象全部扔到存放父類實例的集合。
經過了這個過程,子類實例已經賦值給了父類引用(即完成了向上轉型),但很遺憾的丟失了子類擴展的方法。
   很好的是Java語言有個向下轉型的特性,讓我們可以重新獲得丟失的方法,即強轉回子類
所以我們需要用到子類實例的時候,就從那個父類集合裏拿出來向下轉型就可以了,一樣可以使用子類實例對象

……

我在搜索java向下轉型的意義時,得到一個比較好的答案是這樣的:
最大的用處是java的泛型編程,用處很大,Java的集合類都是這樣的。

   而在Android開發中,我們在Layout文件夾,用xml寫的控件。爲什麼能在Activity等組件中通過 findViewById() 方法找到呢?爲什麼 findViewById(R.id.textview) 方法傳入TextView的id後,還要轉型爲TextView呢?這就是 Java 向下轉型的一個應用



轉載自 :https://blog.csdn.net/xyh269/article/details/52231944

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章