Java入門系列-16-繼承

極客大全發表於2018-10-29

這一篇文章教給新手學會使用繼承,及理解繼承的概念。掌握訪問修飾符、掌握 final 關鍵字的用法。

繼承

為什麼要使用繼承

首先我們先看一下這兩個類:

public class Teacher {
    private int teachingAge;
    private String name;
    private int age;
    
    public void teach() {
        
    }
    public void seyHi() {
        System.out.println("我是:"+this.name);
    }
}
public class Student {
    private int studentNo;
    private String name;
    private int age;
    
    public void learn() {
        
    }
    public void seyHi() {
        System.out.println("我是:"+this.name);
    }
}

Student 類和 Teacher 類中有一些相同的屬性和方法,這些都屬於重複程式碼,當一個程式中有大量的類時,就會產生大量的重複程式碼。這些重複的程式碼能不能抽取出來然後供其他類使用以簡化呢,那就是使用繼承

使用繼承優化之後:

建立 inherit 包

父類:(公共程式碼類)

package inherit;

public class People {
    private String name;
    private int age;
    
    public void sayHi() {
        System.out.println("我是:"+this.name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    
}

子類:Student.java

package inherit;

public class Student extends People{
    private int studentNo;
    public void learn() {
        System.out.println("學習課程");
    }
    public int getStudentNo() {
        return studentNo;
    }
    public void setStudentNo(int studentNo) {
        this.studentNo = studentNo;
    }
}

子類:Teacher.java

package inherit;

public class Teacher extends People{
    private int teachingAge;
    
    public void teach() {
        System.out.println("教授課程");
    }
    
    public int getTeachingAge() {
        return teachingAge;
    }

    public void setTeachingAge(int teachingAge) {
        this.teachingAge = teachingAge;
    }
    
}

測試類:

package inherit;

public class TestInherit {
    public static void main(String[] args) {
        //建立Student物件
        Student stu=new Student();
        stu.setName("張三");//父類中繼承過來的方法
        stu.learn();//子類中特有的方法
        stu.sayHi();
        //建立Teacher物件
        Teacher teacher=new Teacher();
        teacher.setName("湯尼");
        teacher.setTeachingAge(2);//子類中特有的方法
        teacher.sayHi();
    }
}

觀察上面示例程式碼我們發現:

1.子類的公共程式碼都可以放在父類中

2.子類可以有自己獨有的方法和屬性

3.子類一旦繼承父類就會擁有父類的屬性和方法

4.將公共程式碼放入父類,更方便統一修改程式碼

繼承的語法

關鍵字:extends

1.編寫父類

public class 父類{
    //公共的屬性和方法
}

2.編寫子類,繼承父類

public class 子類 extends 父類{
    //子類特有的屬性和方法
}

子類只能繼承一個父類

子類訪問父類成員

子類要想訪問父類的成員要使用 super 關鍵字,super 代表父類物件

訪問父類構造方法:

super();//訪問無參構造
super(引數);//訪問有參構造

訪問父類屬性:

super.name;

訪問父類方法:

super.print();

訪問父類構造,必須在子類構造方法中呼叫,必須是第一句

super 只能出現在子類的方法和構造方法中

super 不能訪問父類的 private 成員

敲一敲:訪問父類成員

建立包 visitparent 後在報下建立如下類
父類

package visitparent;

public class Animal {
    private String name;
    private int legs;
    
    public Animal() {
        this.name="無名";
        this.legs=4;
    }
    public Animal(String name,int legs) {
        this.name=name;
        this.legs=legs;
    }
    
    public void eat(String food) {
        System.out.println(name+" 吃食物:"+food);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getLegs() {
        return legs;
    }

    public void setLegs(int legs) {
        this.legs = legs;
    }
    
}

子類

package visitparent;

public class Cat extends Animal{
    private String hairColor;//毛髮顏色
    private int age;
    
    public Cat () {
        super();//呼叫父類無參
    }
    public Cat(String name,int legs,String hairColor,int age) {
        super(name, legs);//這裡呼叫相當於重用父類構造方法了
        this.hairColor=hairColor;
        this.age=age;
        //super(name, legs);//去掉註釋試試
        //this.name="無名";//去掉註釋試試
    }
    public void catchMouse() {
        System.out.println(super.getName()+":抓老鼠");
    }
    
    public void paly() {
        System.out.println(super.getName()+" 玩累了。");
        super.eat("小魚乾");
    }

    public String getHairColor() {
        return hairColor;
    }

    public void setHairColor(String hairColor) {
        this.hairColor = hairColor;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    
}

子類不能繼承父類的 private 成員

子類不能繼承不同包使用預設訪問許可權的成員(預設訪問許可權就是不寫訪問修飾符)

子類不能繼承父類的構造方法

多重繼承的執行流程

在建立子類的時候父類在做什麼?

下面建立3個類觀察執行流程,C類繼承B類,B類繼承A類。

A.java

public class A {
    public A() {
        System.out.println("A類的無參建構函式執行");
    }
}

B.java

public class B extends A{
    public B() {
        System.out.println("B類的無參建構函式執行");
    }
}

C.java

public class C extends B{
    public C() {
        System.out.println("C類的無參建構函式執行");
    }
}

TestRunFlow.java 測試類,展示執行結果

public class TestRunFlow {
    public static void main(String[] args) {
        C c=new C();
    }
}

執行結果為:

A類的無參建構函式執行
B類的無參建構函式執行
C類的無參建構函式執行

如果子類構造方法通過 super 顯式呼叫父類相應構造方法,則不執行父類無參構造方法

子類構造方法預設會呼叫父類無參構造方法

呼叫父類無參構造方法,一直到執行頂級父類Object類的的無參構造方法為止

根據以上規則,判斷下面的程式碼是否能編譯通過

父類

public class Pet {
    private String name;
    public Pet(String name) {
        this.name=name;
    }
}

子類

public class Dog extends Pet{
}

答案是不能,父類中只有有參構造方法沒有無參構造方法,子類中沒有任何程式碼預設有一個隱式無參構造方法,子類無參構造方法預設呼叫父類無參構造方法,然而父類中沒有,所有在子類中報錯。

解決辦法:1.在父類中顯式新增無參構造方法,2.在子類構造方法中顯式呼叫父類有參構造方法。

java 中的訪問修飾符

訪問修飾符 protected 能修飾屬性和方法,修飾後本類、子類、同包可以訪問。

訪問修飾符 本類 同包 子類 其他
private
預設(friendly)
protected
public

方法重寫

在”繼承優化後”的程式碼中,Teacher 繼承了 People 類,(忘記程式碼可以翻回去再看一遍) People 類中有個一個打招呼的方法 sayHi() 用於輸出人的名字,但是 Teacher 呼叫這個方法並不能列印出 Teacher 的屬性 teachingAge 的值,但是我們還想用這個方法實現這個功能,應該怎麼辦呢?

我們可以使用 方法重寫 解決這個問題,修改子類 Teacher 中的程式碼,下面看一下使用方法重寫後的效果。

Teacher.java

package inherit;

public class Teacher extends People{
    //省略其他屬性
    
    @Override
    public void sayHi() {
        System.out.println("我是:"+super.getName()+" ,從事教育行業 "+this.teachingAge+" 年了。");
    }

    //省略其他方法、getter、setter
}

在 Eclipse 中重寫某方法的快捷鍵是 Alt+Shift+S+V ,按完後選擇要重寫的方法

在 Idea 中重寫某方法的快捷鍵是 Ctrl+O ,按完後選擇要重寫的方法

@Override 註解的作用, 用來檢測是否符合重寫規則,不符合重寫規則將報錯,這個註解可以不寫

構造方法不能重寫,因為構造方法不能被繼承

方法重寫的規則:

1.方法名相同

2.引數列表相同

3.返回值型別相同或者是其子類

4.訪問許可權不能嚴於父類

final 關鍵字的使用

1.final 修飾變數後變為常量

private static final long serialVersionUID = -6849794470754667710L;

2.final 修飾類後,該類不能被繼承

package java.lang;
public final class Math {
    //省略屬性和方法……
}

3.final 修飾方法後,該方法不能被重寫

public final void teach() {
        System.out.println("教授課程");
    }

4.final 修飾建立的物件後,該對像不能再次例項化(可以修改屬性)

final Teacher teacher=new Teacher();
teacher.setName("湯尼");
//teacher=new Teacher();//去掉註釋試試

String 類就是一個典型的被 final 修飾的類

搜尋關注公眾號「享智同行」,第一時間獲取技術乾貨


相關文章