開始的時候,總是不理解,為什么Java中要有轉(zhuǎn)型這一概念。但是隨著面向?qū)ο笏枷氲募由?,以及對Java的理解深入。才知道,轉(zhuǎn)型真的是Java的特色,更是好東西啊。
話不多說,直接舉例。
首先,我們有兩個類:父類:動物類,子類:人
public class Animal {
public void eat(){
System.out.println("animal eatting...");
}
}
class Human extends Animal{
public void eat(){
System.out.println("human eatting...");
}
public void study(){
System.out.println("human study...");
}
}
class Main{
public static void main(String[] args) {
Animal b=new Human(); //向上轉(zhuǎn)型
b.eat();
b.study();? //此處提示在Animal中沒有定義study方法。
}
在函數(shù)中,將對象Human向上轉(zhuǎn)型為父類Animal對象,調(diào)用父類的eat方法。這樣看起來沒有什么,但是,實際上在我們實際編程中節(jié)約了很大的代碼量。想象一下,如果沒有向上轉(zhuǎn)型的情況。(粘貼一下別人的代碼,轉(zhuǎn)自六易金鱗http://blog.csdn.net/shanghui815/article/details/6088588)
來看下面的顯示器類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");
}
}
現(xiàn)在有一個MyMonitor類。假設(shè)沒有向上轉(zhuǎn)型,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();
}
}
可能你已經(jīng)意識到上述代碼有很多重復(fù)代碼,而且也不易維護(hù)。有了向上轉(zhuǎn)型,代碼可以更為簡潔:
package a.b;
public class MyMonitor {
public static void main(String[] args) {
run(new LCDMonitor()); ??????????????????? //向上轉(zhuǎn)型
run(new CRTMonitor());???????????????????? //向上轉(zhuǎn)型
run(new PlasmaMonitor());??????????? //向上轉(zhuǎn)型
}
public static void run(Monitor monitor) { //父類實例作為參數(shù)
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可以不不作任何修改。
可以看出,向上轉(zhuǎn)型體現(xiàn)了類的多態(tài)性,增強(qiáng)了程序的簡潔性。
回到我們的Animal上面來。為什么,調(diào)用study()方法會出錯呢?因為向上轉(zhuǎn)型父類指向子類引用對象會遺失除與父類對象共有的其他方法,也就是在轉(zhuǎn)型過程中,子類的新有的方法都會遺失掉,在編譯時,系統(tǒng)會提供找不到方法的錯誤。但是如果子類重寫了父類的方法就根據(jù)這個引用指向調(diào)用子類重寫的這個方法(這個方法就是覆蓋override)。這個調(diào)用過程就稱為“動態(tài)綁定”。
好了,再來說一下向下轉(zhuǎn)型:
主要分為兩種情況:
情況一:如果父類引用的對象如果引用的是指向的子類對象,那么在向下轉(zhuǎn)型的過程中是安全的。也就是編譯是不會出錯誤的。
情況二:如果父類引用的對象是父類本身,那么在向下轉(zhuǎn)型的過程中是不安全的,編譯不會出錯,但是運(yùn)行時會出現(xiàn)java.lang.ClassCastException錯誤。它可以使用instanceof來避免出錯此類錯誤。
還是用Animal的例子:
public class Animal {
public void eat(){
System.out.println("animal eatting...");
}
}
class Human extends Animal{
public void eat(){
System.out.println("human eatting...");
}
public void study(){
System.out.println("human study...");
}
}
class Main{
public static void main(String[] args) {
Animal b=new Human(); //向上轉(zhuǎn)型
b.eat();
Human h = (Human)b;//向下轉(zhuǎn)型,編譯和運(yùn)行皆不會出錯
h.eat();
h.study();
Animal b=new Animal();
b.eat();
//Human h2 = (Human)b2;//不安全的向下轉(zhuǎn)型,編譯無錯但會運(yùn)行會出錯
//h2.eat();
//h2.study();
//以此這種向下轉(zhuǎn)型應(yīng)該這樣寫
if(b2 instanceof Human){
Human h2 = (Human)b2;
h2.eat();
h2.study();
}
總結(jié):
1、父類引用可以指向子類對象,子類引用不能指向父類對象。
2、把子類對象直接賦給父類引用叫upcasting向上轉(zhuǎn)型,向上轉(zhuǎn)型不用強(qiáng)制轉(zhuǎn)型。就像例子:Animal animal = new Human();
3、把指向子類對象的父類引用賦給子類引用叫向下轉(zhuǎn)型(downcasting),要強(qiáng)制轉(zhuǎn)型。
如Animal就是一個指向子類對象的父類引用,把Animal賦給子類引用human 即Human human =(Human)animal;其中animal前面的(Human)必須添加,進(jìn)行強(qiáng)制轉(zhuǎn)換。
4、向上轉(zhuǎn)型(upcasting) 會丟失子類特有的方法,但是子類覆蓋(overriding) 父類的方法,子類方法有效
5、向上轉(zhuǎn)型的作用,減少重復(fù)代碼,父類為參數(shù),調(diào)有時用子類作為參數(shù),就是利用了向上轉(zhuǎn)型。這樣使代碼變得簡潔。體現(xiàn)了JAVA的抽象編程思想。
每天進(jìn)步一點點
推薦微信公眾號【排骨肉段】,記錄日常的美好。