1. 程式人生 > >java父類子類上下轉型總結

java父類子類上下轉型總結

介面的最主要的作用是達到統一訪問,就是在建立物件的時候用介面建立,【介面名】 【物件名】=new 【實現介面的類】,這樣你像用哪個類的物件就可以new哪個物件了,不需要改原來的程式碼,就和你的USB介面一樣,插什麼讀什麼,就是這個原理。就像你問的,都有個method1的方法,如果我用介面,我上面就可以one.method1();是吧?那樣我new a();就是用a的方法,new b()就是用b的方法
這樣不方便嗎?
這個就叫統一訪問,因為你實現這個介面的類的方法名相同,但是實現內容不同
我用介面來定義物件不就可以做到統一訪問了嗎?介面主要針對多個類實現它來說的,要是隻有一個類當然可以不用介面了.你這樣想,我做一個USB介面,有個read()抽象方法,然後mp3類實現,U盤類實現,行動硬碟類實現,這樣我用的時候用USB a=new 【類名】;這樣a.read();要是我類名裡寫U盤,就讀U盤,寫mp3就讀mp3,而這個名字可以從屬性檔案裡讀,你寫哪個就用哪個了,呵呵。
介面是 java 多型的一種形式 
interface A { public void print();} 
class B 和 class C 都實現了介面 a 
class D { 
public void d(A a){ a.print();} 
//這個方法要求傳一個A物件的引用 ,這裡只要是實現了介面A的物件都可以做為引數,會呼叫這個物件所實現的print()方法,有點像繼承過載,但是介面更靈活,可以實現多個介面,繼承只能繼承一個父類. 
面向物件程式設計有三個特徵,即封裝、繼承和多型。

向上轉型可以像下面這條語句這麼簡單:

  Shape s =new Circle();

  這裡,建立一個Circle物件,並把得到的引用立即賦值給S矇,這樣做看似錯誤(將一種型別賦值給別一種型別);但實際上沒有問題,因為通過繼承,Circle就是一種Shape。因此,編譯器認可這條語句,也就不會產生錯誤資訊。

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

轉型例子:

public class A {
public void aMthod() { 
      System.out.println("A method"); 

}

public class B extends A {
public String name ;
void bMethod1() {  System.out.println("B method 1" + name );} 
void bMethod2() {  System.out.println("B method 2" + name ); } 
}

public static void main(String[] args) {
A a1 = new B(); // 向上轉型 
         a1.aMthod();    // 呼叫父類aMthod(),a1遺失B類方法bMethod1()、bMethod2() 
         
         B bb = (B) a1; // 正常的,因為bb指向的是B子類,呼叫的也是B子類的方法。
         bb.name = "sun";
         bb.aMthod();   // 而這樣的a1父類,必須是指向過子類,才可以向下轉型。
         bb.bMethod1(); // sun可以列印


  // 當向下轉型的時候,最後的子類bb可以像子類一樣使用,如果沒使用之前,子類bb列印的name是Null.主要是bb用了指向子類的父類,才可以向下轉型,如果父類a1指向父類,就沒辦法轉型了。
         A a2 = new A(); 
         B b2 = (B) a2; // 向下轉型,編譯無錯誤,執行時將出錯 
         b2.aMthod(); 
         b2.bMethod1(); 
         b2.bMethod2(); 

}

其實黑體部分的向下轉型程式碼後的註釋已經提示你將發生執行時錯誤。為什麼前一句向下轉型程式碼可以,而後一句程式碼卻出錯?這是因為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異常了。

1。父類引用指向子類物件,而子類引用不能指向父類物件。

2。把子類物件直接賦給父類引用叫upcasting向上轉型,向上轉型不用強制轉換。

      如:Father f1 = new Son();

3。把指向子類物件的父類引用賦給子類引用叫向下轉型(downcasting),要強制轉換。

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

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

當在父類和子類中同時定義和賦值同名的成員變數name,並試圖輸出該變數的值時,父類引用輸出的是父類的成員變數,也就是

父類的引用,按照道理只能呼叫父類的成員變數和函式,如果子類重寫了父類的函式,就變成了多型,正好應驗了父類引用指向子類物件的情況下多型的應用。

二.注意事項:

     (1)向上轉型的物件的引用呼叫的方法是子類的。

     (2)但如果呼叫的方法父類中沒有的話則會報錯。(意思是隻能呼叫子類中過載父類的方法)

     (3)父類的引用可以指向子類的物件,但是子類的引用不能指向父類的物件。

    子類的物件呼叫到的成員變數,是父類的成員變數(此時要想訪問子類的成員變數,就要呼叫setter getter函數了[應該是覆寫過的],情況跟多型一樣)。

對於多型,可以總結它為:

    一、使用父類型別的引用指向子類的物件;該引用只能呼叫父類中定義的方法和變數;

    二、如果子類中重寫了父類中的一個方法,那麼在呼叫這個方法的時候,將會呼叫子類中的這個方法;(動態連線、動態呼叫)

    三、變數不能被重寫(覆蓋),”重寫“的概念只針對方法。

-------------------------------- 華麗的分割線  深入理解java上下轉型--------------------------------------

1. 引用在棧記憶體中存在物件的記憶體地址。真正的物件(通過 new Student()建立的)存放在堆記憶體裡。

在這塊堆記憶體區域內,存在的是子類的屬性(包括自己特有的,以及通過super()構造方法中從父類獲得的)

和方法(繼承父類但沒有覆蓋的,以及覆蓋父類的方法和自己特有的),儘管引用是宣告為父類的引用,

但是它指向的子類的物件,在執行方法的時候,是通過引用指向的堆記憶體區域內執行的。也就是到底執行父類

方法還是子類方法是由物件決定的,跟引用沒有直接關係。

2.
從物件的記憶體角度來理解試試.
假設現在有一個父類Father,它裡面的變數需要佔用1M記憶體.有一個它的子類Son,它裡面的變數需要佔用0.5M記憶體.
現在通過程式碼來看看記憶體的分配情況:
Father f = new Father();//系統將分配1M記憶體.
Son s = new Son();//系統將分配1.5M記憶體!因為子類中有一個隱藏的引用super會指向父類例項,所以在例項化子類之前會先例項化一個父類,也就是說會先執行父類的建構函式.由於s中包含了父類的例項,所以s可以呼叫父類的方法.
Son s1 = s;//s1指向那1.5M的記憶體.
Father f1 = (Father)s;//這時f1會指向那1.5M記憶體中的1M記憶體,即是說,f1只是指向了s中例項的父類例項物件,所以f1只能呼叫父類的方法(儲存在1M記憶體中),而不能呼叫子類的方法(儲存在0.5M記憶體中).
Son s2 = (Son)f;//這句程式碼執行時會報ClassCastException.因為f中只有1M記憶體,而子類的引用都必須要有1.5M的記憶體,所以無法轉換.
Son s3 = (Son)f1;//這句可以通過執行,這時s3指向那1.5M的記憶體.由於f1是由s轉換過來的,所以它是有1.5M的記憶體的,只是它指向的只有1M記憶體.

 -------------------------------- 華麗的分割線  多型總結--------------------------------------

對於多型,可以總結它為:       

    一、使用父類型別的引用指向子類的物件;

    二、該引用只能呼叫父類中定義的方法和變數;

    三、如果子類中重寫了父類中的一個方法,那麼在呼叫這個方法的時候,將會呼叫子類中的這個方法;(動態連線、動態呼叫)

    四、變數不能被重寫(覆蓋),”重寫“的概念只針對方法,如果在子類中”重寫“了父類中的變數,那麼在編譯時會報錯。

多型的3個必要條件:

    1.繼承   2.重寫   3.父類引用指向子類物件。