Java 轉型問題(向上轉型和向下轉型)

Java 轉型問題其實並不複雜,只要記住一句話:父類引用指向子類對象。java

什麼叫父類引用指向子類對象?編程

從 2 個名詞開始提及:向上轉型(upcasting) 、向下轉型(downcasting)安全

舉個例子:有2個類,Father 是父類,Son 類繼承自 Father。函數

第 1 個例子:spa

Father f1 = new Son();   // 這就叫 upcasting (向上轉型)
// 如今 f1 引用指向一個Son對象

Son s1 = (Son)f1;   // 這就叫 downcasting (向下轉型)
// 如今f1 仍是指向 Son對象

第 2 個例子:對象

Father f2 = new Father();
Son s2 = (Son)f2;       // 出錯,子類引用不能指向父類對象

你或許會問,第1個例子中:Son s1 = (Son)f1; 問爲何是正確的呢。繼承

很簡單由於 f1 指向一個子類對象,Father f1 = new Son(); 子類 s1 引用固然能夠指向子類對象了。接口

而 f2 被傳給了一個 Father 對象,Father f2 = new Father(); 子類 s2 引用不能指向父類對象。io

總結:編譯

一、父類引用指向子類對象,而子類引用不能指向父類對象。

二、把子類對象直接賦給父類引用叫upcasting向上轉型,向上轉型不用強制轉換嗎,如:

Father f1 = new Son();

三、把指向子類對象的父類引用賦給子類引用叫向下轉型(downcasting),要強制轉換,如:

f1 就是一個指向子類對象的父類引用。把f1賦給子類引用 s1 即 Son s1 = (Son)f1;

其中 f1 前面的(Son)必須加上,進行強制轉換。

1、向上轉型。

通俗地講便是將子類對象轉爲父類對象。此處父類對象能夠是接口。

一、向上轉型中的方法調用:

實例

複製代碼

1 public class Animal {
 2   
 3   public void eat(){
 4     System.out.println("animal eatting...");
 5   }
 6 }
 7 class Bird extends Animal{
 8   
 9   public void eat(){
10     System.out.println("bird eatting...");
11   }
12   
13   public void fly(){
14     
15     System.out.println("bird flying...");
16   }
17 }
18 class Main{
19    public static void doEat(Animal h) {
20     h.eat();
21   }
22   public static void main(String[] args) {
23     
24     Animal b=new Bird(); //向上轉型
25     b.eat(); 
26     //! error: b.fly(); b雖指向子類對象,但此時丟失fly()方法
27     Animail c1=new Animal();
28     Bird c2=new Bird();
29     doEat(c1);
30     doEat(c2);//此處參數存在向上轉型
31   }
32 }

複製代碼

 

注意這裏的向上轉型:

Animal b=new Bird(); //向上轉型
b.eat();

此處將調用子類的 eat() 方法。緣由:b 實際指向的是 Bird 子類,故調用時會調用子類自己的方法。

須要注意的是向上轉型時 b 會遺失除與父類對象共有的其餘方法。如本例中的 fly 方法再也不爲 b 全部。

二、向上轉型的做用

看上面的代碼:

public static void doEate(Animail h) {
    h.sleep();
}

這裏以父類爲參數,調有時用子類做爲參數,就是利用了向上轉型。這樣使代碼變得簡潔。否則的話,若是 doEate 以子類對象爲參數,則有多少個子類就須要寫多少個函數。這也體現了 JAVA 的抽象編程思想。

2、向下轉型。

與向上轉型相反,便是把父類對象轉爲子類對象。

實例

 

複製代碼

public class Animail {
    private String name="Animail";
    public void eat(){
        System.out.println(name+" eate");
    }
}

class Human extends Animail{
    private String name="Human";
    public void eat(){
        System.out.println(name+" eate");
    }
}

class Main {
    public static void main(String[] args) {
        Animail a1=new Human();//向上轉型
        Animail a2=new Animail();
        Human b1=(Human)a1;// 向下轉型,編譯和運行皆不會出錯
 //       Human c=(Human)a2;//不安全的向下轉型,編譯無錯但會運行會出錯
    }
}

實例

複製代碼

 

Animail a1=new Human();//向上轉型
Human b1=(Human)a1;// 向下轉型,編譯和運行皆不會出錯

這裏的向下轉型是安全的。由於 a1 指向的是子類對象。

Animail a2=new Animail();
Human c=(Human)a2;//不安全的向下轉型,編譯無錯但會運行會出錯
 

運行出錯:

Exception in thread "main" java.lang.ClassCastException: study.轉型實例.Animail cannot be cast to study.轉型實例.Human
at study.轉型實例.Main.main(Main.java:8)

向下轉型的做用

向上轉型時 b會遺失除與父類對象共有的其餘方法;能夠用向下轉型在從新轉回,這個和向上轉型的做用要結合理解。

 

3、當轉型遇到重寫和同名數據

看下面一個例子,你以爲它會輸出什麼?

複製代碼

public class A {
   public int i=10;
   void print(){
       System.out.println("我是A中的函數");
   }
}
class B extends A{
   public int i=20;
    void print(){
        System.out.println("我是B中的函數,我重寫了A中的同名函數");
    }
    void speek(){
        System.out.println("向上轉型時我會丟失");
    }

   public static void main(String[] args) {
        B b=new B();
        A a=b;//此處向上轉型
        b.print();  System.out.println(b.i);
        b.speek();
        a.print();  System.out.println(a.i);
       ((B) a).speek();//a在建立時雖然丟失了speek方法可是向下轉型又找回了

    }
}

複製代碼

結果

我是B中的函數,我重寫了A中的同名函數
20
向上轉型時我會丟失
我是B中的函數,我重寫了A中的同名函數
10
向上轉型時我會丟失

咱們發現同名數據是根據建立對象的對象類型而肯定,而這個子類重寫的函數涉及了多態,重寫的函數不會由於向上轉型而丟失

多態存在的三個必要條件

  • 繼承
  • 重寫
  • 父類引用指向子類對象

因此不要弄混淆了,父類的方法在重寫後會被子類覆蓋,當須要在子類中調用父類的被重寫方法時,要使用super關鍵字

相關文章
相關標籤/搜索