1. 程式人生 > >廖雪峰Java2面向對象編程-3繼承和多態-1繼承

廖雪峰Java2面向對象編程-3繼承和多態-1繼承

需要 except ati 復用 強制 cte end 繼承 println

1.繼承

技術分享圖片
繼承是一種代碼復用的方式.
Student與Person有相同部分的代碼。
Student可以從Person繼承,這樣Student獲得了Person的所有功能,只需要編寫新增的功能即可。通過繼承,可以實現代碼的復用。

繼承使用關鍵字extends,一個類只能有一個父類。
如果沒有寫明繼承類,編譯器會自動指定該類繼承於基類Object。
Person:超類super,父類,基類
Student:子類subclass,擴展類

Person.java

//默認繼承Object
public class Person /*extends Object */{
    private String name;
    private int age;
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
    public void setAge(){
        this.age = age;
    }
    public int getAge(){
        return this.age;
    }
    public void run(){
        System.out.println(name+" is running!");
    };
}

Student.java

public class Student extends Person{
    private int score;
    public void setScore(int score){
        this.score = score;
    }
    public int getScore(){
        return this.score;
    }
}

Hello.java

public class Hello {
    public static void main(String[] args){
        Person ming = new Person();
        Student hong = new Student();
        ming.setName("小明");
        hong.setName("小紅");
        ming.run();
        hong.run();
    }
}

技術分享圖片

2.protected

上例中Person類定義的private字段無法被子類訪問,用protected修飾的字段可以被子類訪問。
protected把字段和方法的訪問權限控制在繼承樹內部
Person.java

public class Person /*extends Object */{
    protected String name; //將name的修飾符更改為protected
    private int age;
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
    public void setAge(){
        this.age = age;
    }
    public int getAge(){
        return this.age;
    }
    public void run(){
        System.out.println(name+" is running!");
    };
}

Student.java

public class Student extends Person{
    private int score;
    public void setScore(int score){
        this.score = score;
    }
    public int getScore(){
        return this.score;
    }
    public String hello(){
        return "Hello, " + this.name; //引用name
    }
}
public class Hello {
    public static void main(String[] args){
        Person ming = new Person();
        Student hong = new Student();
        ming.setName("小明");
        hong.setName("小紅");
        ming.run();
        System.out.println(hong.hello());//引用hello方法
        hong.run();
    }
}

3.繼承關系中的構造方法

編寫Person類時,可以編寫構造方法,或由編譯器自動生成構造方法。由於子類包含有父類的所有功能,必須手動調用父類的構造方法。
Java語言規定,子類的構造方法第一行語句必須調用父類的構造方法。調用方式是super();
如果我們沒有寫super(),編譯器會自動生成super()。如果父類沒有默認的構造方法,此時編譯器自動生成的構造方法會報錯,因為父類的構造方法必須傳入參數。此時我們需要顯式的寫上super,傳入參數。
Person.java

public class Person /*extends Object */{
    protected String name;
    private int age;
    public Person(){    //默認的構建方法
        this.name = "王重陽";
    }
    public Person(String name){
        this.name = name;
    }
    public void setAge(int age){
        this.age = age;
    }
    public int getAge(){
        return this.age;
    }
    public void run(){
        System.out.println(name+" is running!");
    };
}

Student.java

public class Student extends Person{
    public Student(){ 
            //根據父類默認的構建方法,自動生成super();
    }    
    public Student(String name){
        super(name);
    }
    private int score;
    public void setScore(int score){
        this.score = score;
    }
    public int getScore(){
        return this.score;
    }
}

Hello.java

public class Hello {
    public static void main(String[] args){
        Student p = new Student("林朝英");
        Student s = new Student();
        p.run();
        s.run();
    }
}

技術分享圖片

4.向上轉型

定義一個類時,實際是定義一個數據類型;定義繼承時,是在數據類型之間加上了繼承的關系。
定義一個實例對象時,需要把它賦值給一個引用類型的變量,讓這個變量指向實例對象。
向上轉型把一個子類型安全地變為更加抽象的類型(父類型)。
反過來,即向下轉型是把一個父類型(抽象)變成一個自類型(具體)。如把一個Person類型變量強制轉型為Student類型變量。
可以對實例變量進行向上轉型(upcasting)和向下轉型(downcasting)

        //假如我們持有一個Student對象實例,name我們可以保證Student包含Person類型的全部功能,因此把它看成一個Person類型對象是沒有問題的。
        Student s = new Student("jack");
        Person ps = s;
        Student s2 = (Student) ps;
        s2.run();

技術分享圖片

        /*Person實例p可能指向Person實例,也可能指向Student實例。向下轉型為Student很有可能報錯。如果變量p指向的實際類型並不是Student實例,JVM運行時會拋出ClassCastException的錯誤。*/
        Person p = new Person("tom");
        Student s2 = (Student) p;
        s2.run();

技術分享圖片

4.1instanceof操作符

public class Hello {
    public static void main(String[] args){
        Person p = new Person("tom");
        System.out.println(p instanceof Person);
        System.out.println((p instanceof Student ) + "\n");

        Student s = new Student("jack");
        System.out.println(s instanceof Person);
        System.out.println((s instanceof Student) + "\n");

        Student n = null;
        System.out.println(n instanceof Object);
        System.out.println(n instanceof Person);
        System.out.println(n instanceof Student);
    }
}

技術分享圖片
使用instanceof修改向下轉型代碼

Person p = new Person("tom");
        Student s = new Student("jack");
        Person ps = s;
        if(p instanceof  Student) { //只在類型正確時轉型,避免異常
            Student s2 = (Student) p;
            s2.run();
        }

技術分享圖片

5.繼承和組合

組合需要在看

public class Student extends Person{
    private Book book;
    public Student(String name){
        super(name);
    }
    private int score;
    public void setScore(int score){
        this.score = score;
    }
    public int getScore(){
        return this.score;
    }
    ...
}

6.總結:

繼承是面向對象編程的一種代碼復用方式。
Java只允許單繼承
protected允許子類訪問父類的字段和方法
子類的構造方法可以通過super()調用父類的構造方法
可以安全地向上轉型為更為抽象的類型
可以強制向下轉型,最好借助instanceof判斷
子類和父類的關系是is,has關系不能用繼承

廖雪峰Java2面向對象編程-3繼承和多態-1繼承