夯實Java基礎(三)——面向對象之繼承

一、繼承概述

繼承是Java面向對象的三大特徵之一,是比較重要的一部分,與後面的多態有着直接的關係。繼承就是子類繼承父類的特徵和行爲,使得子類對象(實例)具備父類的實例域和方法,或子類從父類繼承方法,使得子類具備父類相同的行爲。java

①、Java繼承的特色:this

  • Java只支持單繼承 ,不支持多繼承(如A繼承B,A繼承C),但支持多層繼承(如A繼承B,B繼承C) 。
  • 子類擁有父類非private的屬性,方法。(其實子類繼承父類後,仍然認爲獲取了父類的private結構,只是由於封裝的影響,使得子類不能直接調用父類的結構而已)
  • 子類能夠擁有本身的屬性和方法,即子類能夠對父類進行擴展。
  • 子類能夠用本身的方式實現父類的方法。
  • 提升了類之間的耦合性(繼承的缺點,耦合度高就會形成代碼之間的聯繫)。

②、繼承的好處:spa

  • 減小代碼的冗餘,提升代碼的複用性。
  • 便於功能的擴展。
  • 爲後面多態的使用提供了前提。

③、類的繼承格式:code

在Java中經過 extends 關鍵字來實現繼承關係,形式以下:對象

class 父類 {
    屬性、方法
}
 
class 子類 extends 父類 {
    屬性、方法
}

 提到Java的繼承,確定離不開this,super關鍵字和構造器的使用,下面來介紹一下:blog

二、this、super關鍵字

this關鍵字:表示引用當前對象或正在建立的對象。可用於調用本類的屬性、方法、構造器。繼承

public class Test {
    public static void main(String[] args) {
        Father father=new Father("tang_hao",20);
        father.show();
    }
}
class Father{
    String name;
    int age;

    public Father() {
    }

    public Father(String name) {
        //調用本類的無參構造器
        this();
        this.name = name;
    }

    public Father(String name, int age) {
        //調用本類的有參構造器
        this(name);
        this.age = age;
    }

    public void show(){
        System.out.println("name"+this.name+",age"+this.age);
    }
}

super關鍵字:表示引用當前對象的父類。可用於調用父類的屬性、方法、構造器。編譯器

public class Test {

    public static void main(String[] args) {
        Son son=new Son();
        son.show();
    }
}
class Father{
    String name="Father";
    int age=40;

    public Father() {
        System.out.println("調用了父類的無參構造器");
    }

    public void show(){
        System.out.println("父類的Show方法");
    }
}

class Son extends Father{
    String name="Son";
    int age=20;

    public Son() {
        //調用父類構造器
        super();
    }

    public void show(){
        System.out.println("子類的Show方法");
        System.out.println("本類屬性:"+this.name+","+this.age);
        //調用父類方法
        super.show();
        System.out.println("父類屬性:"+super.name+","+super.age);
    }
}

注意:在使用this、super調用構造器的時候,this、super語句必須放在構造方法的第一行,不然編譯會報錯。不能在子類中使用父類構造方法名來調用父類構造方法。 父類的構造方法不被子類繼承。調用父類的構造方法的惟一途徑是使用 super 關鍵字,若是子類中沒顯式調用,則編譯器自動將 super();也就是說會一直調到Object類,由於Object是全部類的父類。靜態方法中不能使用 super 關鍵字。編譯

三、構造器

前面講到子類能夠繼承父類的非private修飾的屬性和方法,那麼咱們思考一下?父類的構造器可以被子類繼承嗎?答案是:不能!對於構造器而言,它只可以被調用,而不能被繼承。 調用父類的構造方法咱們使用super()便可。class

咱們先來看一個示例:

public class Father {
    protected String name;//姓名
    protected int age;//年齡

    public Father(){
        System.out.println("Father constructor");
    }

    public void eat(){
        System.out.println("Father eat...");
    }

    public void sleep(){
        System.out.println("Father sleep...");
    }
}

class Son extends Father{
    protected String name;//姓名
    protected int age;//年齡

    public Son() {
        System.out.println("Son constructor");
    }

    public void eat() {
        System.out.println("Son eat...");
    }

    public void sleep() {
        System.out.println("Son sleep...");
    }

    public static void main(String[] args) {
        Son son=new Son();
        son.eat();
        son.sleep();
    }
}

運行結果:

從運行的結果來看,咱們只new了Son的實例,可是卻調用父類的無參構造器,並且先輸出了父類構造器的語句。這是由於:若是子類中沒顯式調用父類構造器,則編譯器會自動在構造器方法第一行加上super()。

經過這個示例能夠看出,構建過程是從父類「向外」擴散的,也就是從父類開始向子類一級一級地完成構建。並且咱們並無顯示的引用父類的構造器,這就是java的聰明之處:編譯器會默認給子類調用父類的構造器。

可是,這個默認調用父類的構造器是有前提的:父類有默認構造器。若是父類沒有默認構造器,咱們就要必須顯示的使用super()來調用父類構造器,不然編譯器會報錯:沒法找到符合父類形式的構造器。

public class Father {
    protected String name;//姓名
    protected int age;//年齡

    public Father(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat(){
        System.out.println("Father eat...");
    }

    public void sleep(){
        System.out.println("Father sleep...");
    }
}

class Son extends Father{
    protected String name;//姓名
    protected int age;//年齡

    public Son(String name, int age) {
        //這裏父類沒有默認構造器,因此必須顯式的使用super()
        super("tang_hao",22);
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println("Son eat...");
    }

    public void sleep() {
        System.out.println("Son sleep...");
    }

    public static void main(String[] args) {
        Son son=new Son("tang_hao",20);
        son.eat();
        son.sleep();
    }
}

小結:子類會默認使用super()調用父類默認構造器,若是父類沒有默認構造器,則子類必須顯式的使用super()來調用父類構造器,並且super()必需要放在子類構造方法的第一行。

四、繼承帶來的問題

  1. 子類與父類存在嚴重的耦合關係。
  2.  繼承破壞了父類的封裝性。
  3. 子類繼承父類的屬性和方法,也就說明能夠從子類中惡意修改父類的屬性和方法。

因此能不使用繼承關係就儘可能不要使用繼承。

五、什麼時候使用繼承

  1. 子類須要額外增長屬性,而不只僅是屬性值的改變。
  2. 子類須要增長本身獨有的行爲方式(包括增長新的方法或重寫父類的方法)。
相關文章
相關標籤/搜索