首頁 > Java > java教程 > 主體

Java 轉型實例:向上或向下轉型

PHPz
發布: 2017-03-12 15:40:26
原創
1784 人瀏覽過

這篇文章主要介紹了Java 轉型(向上或向下轉型)詳解及簡單實例的相關資料,需要的朋友可以參考下

在Java編程中經常碰到類型轉換,物件類型轉換主要包括向轉型和向下轉型。

向轉型

我們現實中常常這樣說:這個人會唱歌。在這裡,我們並不關心這個人是黑人還是白人,是成年人還是小孩,也就是說我們更傾向於使用抽象概念「人」。再例如,麻雀是鳥類的一種(鳥類的子類),而鳥類則是動物中的一種(動物的子類)。我們現實中也常這樣說:麻雀是鳥。這兩種說法其實就是所謂的向轉型,通俗地說就是子類轉型成父類。這也符合Java所提倡的面向抽象程式設計思想。來看下面的程式碼:


package a.b; 
public class A { 
public void a1() { 
    System.out.println("Superclass"); 
} 
}
登入後複製

A的子類別B:

package a.b; 
public class B extends A { 
public void a1() { 
    System.out.println("Childrenclass"); //覆盖父类方法 
} 
    public void b1(){} //B类定义了自己的新方法 
}
登入後複製

C類別:

package a.b; 
public class C { 
public static void main(String[] args) { 
    A a = new B(); //向上转型 
    a.a1(); 
} 
}
登入後複製

如果執行C,輸出的是Superclass 還是Childrenclass?不是你原來預期的Superclass,而是Childrenclass。這是因為a實際上指向的是子類別物件。當然,你不用擔心,Java虛擬機會自動精確地辨識出究竟該呼叫哪個具體的方法。不過,由於向上轉型,a物件會遺失和父類別不同的方法,例如b1()。有人可能會提出疑問:這不是多此一舉嗎?我們完全可以這樣寫:


B a = new B(); 
a.a1();
登入後複製

確實如此!但這樣就喪失了面向抽象的程式設計特色,降低了可擴展性。其實,不僅如此,向上轉型還可以減輕程式設計工作量。來看下面的顯示器類別Monitor:

package a.b; 
public class Monitor{ 
public void displayText() {} 
public void displayGraphics() {} 
}
登入後複製

液晶顯示器類別LCDMonitor是Monitor的子類別:


package a.b; 
public class LCDMonitor extends Monitor { 
public void displayText() { 
    System.out.println("LCD display text"); 
} 
public void displayGraphics() { 
    System.out.println("LCD display graphics"); 
} 
}
登入後複製

陰極射線管顯示器類別CRTMonitor自然也是Monitor的子類別:

package a.b; 
public class CRTMonitor extends Monitor { 
public void displayText() { 
    System.out.println("CRT display text"); 
} 
public void displayGraphics() { 
    System.out.println("CRT display graphics"); 
} 
}
登入後複製

等離子顯示器PlasmaMonitor也是Monitor的子類別:


package a.b; 
public class PlasmaMonitor extends Monitor { 
public void displayText() { 
    System.out.println("Plasma display text"); 
} 
public void displayGraphics() { 
    System.out.println("Plasma display graphics"); 
} 
}
登入後複製

現在有一個MyMonitor類別。假設沒有向上轉型,MyMonitor類別程式碼如下:

package a.b; 
public class MyMonitor { 
public static void main(String[] args) { 
    run(new LCDMonitor()); 
    run(new CRTMonitor()); 
    run(new PlasmaMonitor()); 
} 
public static void run(LCDMonitor monitor) { 
    monitor.displayText(); 
    monitor.displayGraphics(); 
} 
public static void run(CRTMonitor monitor) { 
    monitor.displayText(); 
    monitor.displayGraphics(); 
} 
public static void run(PlasmaMonitor monitor) { 
    monitor.displayText(); 
    monitor.displayGraphics(); 
} 
}
登入後複製

可能你已經意識到上述程式碼有很多重複程式碼,而且也不容易維護。有了向上轉型,程式碼可以更為簡潔:


package a.b; 
public class MyMonitor { 
public static void main(String[] args) { 
    run(new LCDMonitor());           //向上转型 
    run(new CRTMonitor());           //向上转型 
    run(new PlasmaMonitor());      //向上转型 
} 
public static void run(Monitor monitor) { //父类实例作为参数 
    monitor.displayText(); 
    monitor.displayGraphics(); 
} 
}
登入後複製

我們也可以採用介面的方式,例如:

package a.b; 
public interface Monitor { 
abstract void displayText(); 
abstract void displayGraphics(); 
}
登入後複製

將液晶顯示器類別LCDMonitor稍作修改:

package a.b; 
public class LCDMonitor implements Monitor { 
public void displayText() { 
    System.out.println("LCD display text"); 
} 
public void displayGraphics() { 
    System.out.println("LCD display graphics"); 
} 
}
登入後複製

CRTMonitor、PlasmaMonitor類別的修改方法與LCDMonitor類似,而MyMonitor可以不作任何修改。

可以看出,向上轉型體現了類別的多態性,增強了程式的簡潔性。

向下轉型

子類別轉型成父類別是向上轉型,反過來說,父類別轉型成子類別就是向下轉型。但是,向下轉型可能會帶來一些問題:我們可以說麻雀是鳥,但不能說鳥就是麻雀。來看下面的範例:

A類別:

package a.b; 
public class A { 
void aMthod() { 
    System.out.println("A method"); 
} 
}
登入後複製

A的子類別B:

package a.b; 
public class B extends A { 
void bMethod1() { 
    System.out.println("B method 1"); 
} 
void bMethod2() { 
    System.out.println("B method 2"); 
} 
}
登入後複製

C類別:

package a.b; 
public class C { 
   public static void main(String[] args) { 
      A a1 = new B(); // 向上转型 
      a1.aMthod();  // 调用父类aMthod(),a1遗失B类方法bMethod1()、bMethod2() 
      B b1 = (B) a1; // 向下转型,编译无错误,运行时无错误 
      b1.aMthod();  // 调用父类A方法 
      b1.bMethod1(); // 调用B类方法 
      b1.bMethod2(); // 调用B类方法 
      A a2 = new A(); 
      B b2 = (B) a2; // 向下转型,编译无错误,运行时将出错 
      b2.aMthod(); 
      b2.bMethod1(); 
      b2.bMethod2(); 
   } 
}
登入後複製

從上面的程式碼我們可以得出這樣一個結論:向下轉型需要使用強制轉換。運行C程序,控制台將輸出:

Exception in thread "main" java.lang.ClassCastException: a.b.A cannot be cast to a.b.B at 
        a.b.C.main(C.java:14) 
A method 
A method 
B method 1 
B method 2
登入後複製

其實黑體部分的向下轉型代碼後的註釋已經提示你將發生運行時錯誤。為什麼前一句向下轉型代碼可以,而後一句代碼卻出錯?這是因為a1指向一個子類別B的對象,所以子類別B的實例物件b1當然也可以指向a1。而a2是父類對象,子類對象b2不能指向父類對象a2。那麼如何避免在執行向下轉型時發生運行時ClassCastException異常?使用5.7.7節學過的instanceof就可以了。我們修改一下C類別的程式碼:

A a2 = new A(); 
if (a2 instanceof B) { 
B b2 = (B) a2; 
b2.aMthod(); 
b2.bMethod1(); 
b2.bMethod2(); 
}
登入後複製

這樣處理後,就不用擔心型別轉換時發生ClassCastException異常了。

以上是Java 轉型實例:向上或向下轉型的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板