天天看點

JAVA可變(協變)傳回類型

在java代碼中,人們慣性的認為一個方法中隻能傳回一種傳回值或者無傳回。部落客在做開發過程中碰到了這樣一種情況,安卓用戶端請求資料,背景可能傳回兩種結果(1)通路令牌失效,無資料傳回。(2)正常擷取資料。

這樣的情況下需要根據通路令牌辨別來判斷是否有資料傳回。當無效時傳回使用者重新登入提示,正常時則傳回資料。顯然,傳回的結果有兩種,那麼一個方法裡面隻能傳回一種類型的禁锢使得開發起來略顯笨拙。 使得開發起來相當難受。

思考良久,又結合C++協變傳回類型的啟發。摘抄原文中的一句話: 在C++中,隻要原來的傳回類型是指向類的指針或引用, 新的傳回類型是指向派生類的指針或引用,覆寫的方法就可以改變傳回類型 。這樣的類型稱為協變傳回類型(Covariant returns type).

因為java裡面有沒有指針,是以無法做到以上的功能。但是派生類是包含父類的共有方法和保護方法的。再根據裡氏代換原則(任何基類可以出現的地方,子類一定可以出現),那麼凡是派生類包含的基類屬性,基類一定包含,這樣的話情況會好很多。 那麼隻要由派生類設定屬性傳回到基類中,基類方法一定能操作這些屬性 。那麼一條完整的可變傳回類型就可以建立起來。下面結合代碼來驗證:

首先先定義兩個實體類,代碼如下,

class Person {
      /** 假設每個人都有一個名字 **/
      String name;
  
      public String getName() {
          return name;
      }
  
      publicvoid setName(String name) {
         this.name = name;
     }
 
 }// person
 
 class SuperMan extends Person {
     /** 假設每個超人都有身高 **/
     int height;
 
     publicint getHeight() {
         return height;
     }
 
     publicvoid setHeight(int height) {
         this.height = height;
     }
 }// SuperMan
           

SuperMan類繼承Person類(部落客當時想不出來什麼好東西了- -!),則SuperMan類包含name和height兩個屬性,基類Person隻包含name屬性。

先說明一下普通的操作方式,以此作為對比。代碼如下:

publicstatic Person getPerson1() {
         Person person = new Person();
         person.setName("無語");
         return person;
     }
           
publicstatic SuperMan getSuperMan1() {
         SuperMan man = new SuperMan();
         man.setName("不知道");
         man.setHeight();
         return man;
     }
           

很簡單,傳回值就是預期的傳回類型,但是如果把傳回類型替換一下結果如何。如下所示:

publicstatic SuperMan getSuperMan() {
         Person person = new SuperMan();
         person.setName("小虎");
         return (SuperMan) person;
     }
           

以上隻能得到Superman的name屬性無法得到height屬性,如果在傳回之前強轉以此加上height屬性後傳回即可得到一個完整的SuperMan對象。這裡不再嘗試,讀者自行處理。

publicstatic Person getPerson() {
         SuperMan man = new SuperMan();
         man.setHeight();
         man.setName("大明");
         return man;
     }
           

以上代碼就是此文章的核心,也是解決文章開頭問題的核心。怎麼操作呢?

我們寫兩個類,ErroMessage和DataMessage類,其中ErroMessage是基類,DataMessage繼承基類。ErroMessage包含erroMessage屬性類型為private,DataMessage包含data屬性。那麼ErroMessage就隻包含erroMessage屬性,操作時隻會引起erroMessage的變化,而不會引起data的變化。而操作DataMessage類時隻能操作data屬性。而在一個方法中,隻要保持方法類型為ErroMessage,傳回時就可以根據需要來傳回相應的類型。這樣使用方法時, 用派生類得到所有屬性,如果子類屬性為空,那麼基類屬性一定不為空。如果派生類屬性不為空,那麼基類屬性一定為空。 這樣就可以按需取得相應的資料。操作起來相當簡單。代碼操作如下:

printDivider("person");
         Person person = getPerson();
         System.out.println("person的名字是" + person.getName());
         SuperMan superMan = (SuperMan) person;
         System.out.println("通過強轉擷取到的超人高度是這樣的" + superMan.getHeight());      

以上就是部落客對可變傳回類型的了解。

其中核心思想是這樣的: 派生類可以包含基類的共有屬性,那麼基類一定能從派生類擷取到自身暴露給派生類屬性的值 。這是一種逆向思維方式,可能有悖于傳統代碼編寫方式,但是做軟體就是應該嘗試打破傳統思維,縱使道路崎岖不堪。如果有錯誤的話,還望各位讀者提出指正批評意見,共同成長。

FROM:http://www.tuicool.com/articles/qUJFbi