1. 程式人生 > >Java基類和派生類

Java基類和派生類

   從外部看來,派生類是一個與基類具有相同介面的新類,或許還會有一些額外的的方法和域 。但繼承並不僅僅是類的複用。當建立了一個派生類的物件時,該類包含了一個基類的子物件。這個子物件和你用基類直接建立的物件沒有什麼兩樣。二者的區別在於,後者來自於外部,而基類的子物件來自於派生類物件的內部。對基類的子物件初始化時至關重要的,而且也只有一種方法來保證這一點,那就是在派生類的構造器中呼叫基類的構造器,而基類的構造器具有執行基類初始化所需的所有能力和知識。

      在無參構造器時, java會自動在派生類的構造器中插入對基類的構造器的呼叫。

Java程式碼
  1. public class Humans {     
  2.     Humans(){  
  3.         System.out.println("我是人!");  
  4.     }  
  5. }  
Java程式碼 
  1. public class Student extends Humans{  
  2.     Student(){  
  3.         System.out.println("我是學生!");  
  4.     }  
  5. }  
Java程式碼
  1. public class test {  
  2.     public static void main(String args[]){  
  3.           new Student();  
  4.     }  
  5. }  

 輸出結果為:

      我是人!

     我是學生!

可以發現,總是基類的構造器先被初始化。

但是當構造器有引數時,那就必須使用關鍵字super現實地編寫呼叫基類構造器的程式碼,並且匹配適當的引數列表。

Java程式碼 
  1. public class Humans {  
  2.     private String name;  
  3.     Humans(String name){  
  4.         System.out.println("我是叫"+name+"的人");  
  5.     }  
  6.     public String getName() {  
  7.         return name;  
  8.     }  
  9.     public
     void setName(String name) {  
  10.         this.name = name;  
  11.     }  
  12. }  
Java程式碼
  1. public class Student extends Humans{  
  2.     private String name;  
  3.     Student(String name){  
  4.         super(name);  
  5.         System.out.println("我是學生!");  
  6.     }  
  7.     public String getName() {  
  8.         return name;  
  9.     }  
  10.     public void setName(String name) {  
  11.         this.name = name;  
  12.     }  
  13. }  
Java程式碼
  1. public class test {  
  2.     public static void main(String args[]){  
  3.         new Student("zhangsan");  
  4.     }  
  5. }  

 輸出結果:

我是叫zhangsan的人

我是學生!

如果註釋掉上面的super(name);將會報錯。原因是派生類必須呼叫基類構造器。因為例項化派生類時,基類也會被例項化,如果不呼叫基類的構造器,基類將不會被例項化,所以派生類沒有呼叫基類構造器會報錯。

但是如果Humans的程式碼變成這樣就不會錯。如下程式碼:

Java程式碼
  1. public class Humans {  
  2.     private String name;  
  3.     Humans(){  
  4.         System.out.println("我是人!");  
  5.     }  
  6.     Humans(String name){  
  7.         System.out.println("我是叫"+name+"的人");  
  8.     }  
  9.     public String getName() {  
  10.         return name;  
  11.     }  
  12.     public void setName(String name) {  
  13.         this.name = name;  
  14.     }  
  15. }  
Java程式碼
  1. public class Student extends Humans{  
  2.     private String name;  
  3.     Student(String name){  
  4.         //super(name);  
  5.         System.out.println("我是學生!");  
  6.     }  
  7.     public String getName() {  
  8.         return name;  
  9.     }  
  10.     public void setName(String name) {  
  11.         this.name = name;  
  12.     }  
  13. }  
Java程式碼
  1. public class test {  
  2.     public static void main(String args[]){  
  3.         new Student("zhangsan");  
  4.     }  
  5. }  

 輸出結果為:

        我是人!

        我是學生!

原因是,如果基類有一個無參的構造器,就算派生類不用super顯示呼叫基類的建構函式,編譯器也會自動

去呼叫基類的無參建構函式。

所以上面的程式碼不會報錯,輸出結果也不是

        我是叫zhangsan的人

        我是學生!

而是

        我是人!

        我是學生!

派生類繼承了基類的所有public和protected屬性和方法,程式碼如下:

Java程式碼
  1. public class Humans {  
  2.     public String sex;  
  3.     protected int age ;  
  4.     private String name;  
  5.     Humans(String sex,String name,int age){  
  6.         this.sex = sex;  
  7.         this.name = name;  
  8.         this.age = age;  
  9.     }  
  10.     public String getName() {  
  11.         return name;  
  12.     }  
  13.     public void setName(String name) {  
  14.         this.name = name;  
  15.     }  
  16. }  
Java程式碼
  1. public class Student extends Humans{  
  2.     Student(String sex ,String name,int age){  
  3.         super(sex,name,age);  
  4.     }  
  5. }  
Java程式碼
  1. public class test {  
  2.     public static void main(String args[]){  
  3.         Student s = new Student("男","zhangsan",10);  
  4.         System.out.println(s.sex);  
  5.         System.out.println(s.name);  
  6.         System.out.println(s.age);  
  7.     }  
  8. }  

 上面的System.out.println(s.name);會報錯,因為name是private屬性,如需訪問,採用get方法:

Java程式碼
  1. System.out.println(s.getName());  

輸出結果為:

zhangsan

10 

如果派生類定義了和基類一樣的屬性或方法,將覆蓋基類的屬性和方法。如將student改為如下程式碼:

Java程式碼
  1. public class Student extends Humans{  
  2.     public String sex;  
  3.     protected int age ;  
  4.     private String name;  
  5.     Student(String sex ,String name,int age){  
  6.         super(sex,name,age);  
  7.     }  
  8.     public String getName() {  
  9.         return name;  
  10.     }  
  11.     public void setName(String name) {  
  12.         this.name = name;  
  13.     }  
  14. }  

 輸出結果為:

null

null

0

因為只有基類的屬性在構造時賦值了,派生類的沒有,當訪問這些屬性時,訪問的是派生類的屬性,所以全為null或者0。

只有當派生類的屬性也被例項化時,才會得到屬性的值。程式碼改為如下:

Java程式碼
  1. public class Student extends Humans{  
  2.     public String sex;  
  3.     protected int age ;  
  4.     private String name;  
  5.     Student(String sex ,String name,int age){  
  6.         super(sex,name,age);  
  7.         this.sex = sex;  
  8.         this.name = name;  
  9.         this.age = age;  
  10.     }  
  11.     public String getName() {  
  12.         return name;  
  13.     }  
  14.     public void setName(String name) {  
  15.         this.name = name;  
  16.     }  
  17. }  

輸出結果為:

zhangsan

10 

要注意的是,super必須在構造器的最前面,不然會報錯