1. 程式人生 > >Java——超類和子類物件之間的轉換

Java——超類和子類物件之間的轉換

繼承是Java中常用的一項特性,通過繼承我們可以省去很多麻煩。

而Java中超類和子類物件之間的轉換則是很多新手的常遇見的難題,要是處理不好,恐怕會因為這個很特殊的問題導致一些潛在的危險,讓你整整一個晚上都在除錯程式以解決一個讓人抓狂的java.lang.ArrayStoreException異常。 

哈哈,所謂救人一bug勝造七級浮屠,今天我們就來理一理Java中超類和子類物件之間的轉換,看看它到底有什麼不一樣!

首先我們要了解一下轉換的概念。

從子類向父類的轉換稱為向上轉換(upcasting),通過向上轉換,我們能夠在編寫程式時採用通用程式設計的思想,在需要使用子類物件的時候,通過把變數定義為父型別,我們可以通過一個變數,使用該父型別的所有子型別例項;從父型別向子型別的轉換稱為向下轉換

(downcasting),通過向下轉換,我們能在必要的時候,將父型別變數轉換成子型別變數,使用一些通過子型別才能夠使用的方法。

那什麼時候可以進行轉換呢?

我們先來說一說向上轉換,這個比較簡單,而且限制還少。

還是老規矩,我們下面來看一段程式碼~~

來呀!!阿福,放程式碼~~~

                        class  Father
    
                       {

                       };

                       class Son extends  publc  Father

                       {    

                       };

                    

                           

在上面的程式中Father為超類,son是father的子類

那如何將子類轉換為超類呢?

  Father  f  =   new  Son();  //父類引用指向子類物件

 顯然,這樣就可以了。需要注意,new  Son()表示在在堆中分配了一段空間來存放類Son中的資料,並返回一個Son的物件,並賦值給Father的引用f,即f指向子類的物件,此時,子類的物件並沒有定義一個名字。

 也就是說上面的語句等價於:

                           Son  s  =   new  Son();

                            Father  f  =  s;
注:父類不可呼叫子類新增的方法,即f不可呼叫s新增的方法。

好啦,子類轉父類就是這樣簡單,接下來該重點看看父類轉子類啦。

按理論上分析的話,父類轉子類是不可以實現的。因為子類繼承於父類,並新增了一些父類並沒有的東西,也就是說,子類物件一般都比父類物件包含更多的東西。這樣的話,子類如果訪問子類新增的內容, 而這些內容父類並沒有,所以就會報錯。

那Java裡面父類到底可不可以轉子類呢?

可以!但是需要滿足一個前提,即該父類物件已經指向了子類物件。

如:

                      Father  f  =   new  Son();  //父類引用指向子類物件

                      Son   s2  =  (Son)f;  //可以

                      因為當子類強制轉換為父類物件時,並沒有實際丟失它原有記憶體空間(比父類多的那些部分)

                      只是暫時不可訪問,所以能再轉回來。

此外,當該父類是呼叫子類構造器建立的時候,它也可以轉換為子類。

如:

Employee b=new Manager("a",1000,2,1,225);//父類呼叫子類的構造器 建立了一個父類物件

這個原理其實和上面的情況一樣,因為它也是父類引用指向了子類物件,因此也可以進行轉換。

 當然,為了防止報ClassCastExcept異常,一般可以在前面加一條判斷句 if(father instanceof Son)

                  如:

                        Father  f  =   new  Son();  //父類引用指向子類物件

                        if(father instanceof Son)

                       {

                                 Son   s2  =  (Son)f;

                      }

這樣就可以避免出錯。

通過上文的瞭解,大家可能心裡已經有了一些理解,最後再提一下物件在繼承關係中的改變

物件的賦值是地址標識的傳遞,即兩個物件名共同使用同一段記憶體地址。在Java中,對父類與子類物件之間的賦值作了如下規定:

1、子類物件名可以賦值給父類物件名;但父類物件名不可以賦值給子類物件名。

即:父類物件名=子類物件名;

2、如果一個父類物件名已經被子類物件名所賦值,那可以將父類物件名經強制轉換賦值給子類物件名。

即:子類物件名=(子類類名)父類物件名;

常用的一種形式:方法中形參用父型別,實參用子類的物件名.

總結

對類進行造型轉換的應參考以下原則:
1.總是可以“父=子”賦值。此時不需要型別轉換。
2.可以執行型別轉換“子=(子)父”,但需要執行時進行檢查。如果父類變數引用的是正確的子型別,賦值將執行。如果父類變數引用的是不相關的子型別,將會生成class castException異常。
即:如果父類的例項是在子類的例項上塑造的,“子=(子)父”時就不會丟擲異常。  
如:
A 是B的父類。
A a= new B(); //父類A的物件a是在子類B的物件上塑造的。
就可以:
B b= (B)a;
3.決不能在不相關的任何類之間執行類的賦值或者型別轉換。即類的造型轉換僅限於有繼承關係的倆個類的物件之間。

 

好啦,如果大家還是不太明白,可以試一試下面的程式,親自上手試一試會了解得更透徹一些。

package inheritance;

public class test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
            
        Employee e;
        Manager boss =new Manager("Searchin",52000,2018,10,25);
        Employee[] staff=new Employee[3];
        staff[0]=boss;//子類轉父類
        Employee b=new Manager("a",1000,2,1,225);//父類呼叫子類的構造器 建立了一個父類物件
        //Manager b=new Employee("a",1000,2,1,225);
        Manager a=(Manager)staff[0];//強制型別轉換
        System.out.println(staff[0].getName());
        System.out.println(a.getName());
        boss.setBonus(5000);
        //staff[0].setBonus(5000);
        
    }

}


 

package inheritance;

import java.time.*;

public class Employee
{
   private String name;
   private double salary;
   private LocalDate hireDay;

   public Employee(String name, double salary, int year, int month, int day)
   {
      this.name = name;
      this.salary = salary;
      hireDay = LocalDate.of(year, month, day);
   }

   public String getName()
   {
      return name;
   }

   public double getSalary()
   {
      return salary;
   }

   public LocalDate getHireDay()
   {
      return hireDay;
   }

   public void raiseSalary(double byPercent)
   {
      double raise = salary * byPercent / 100;
      salary += raise;
   }
}
package inheritance;

public class Manager extends Employee
{
   private double bonus;


   public Manager(String name, double salary, int year, int month, int day)
   {
      super(name, salary, year, month, day);
      bonus = 0;
   }

   public double getSalary()
   {
      double baseSalary = super.getSalary();
      return baseSalary + bonus;
   }

   public void setBonus(double b)
   {
      bonus = b;
   }
}