天天看點

超類、子類之間的繼承、多态

關鍵字 extends 表示 繼承。

  • 已存在的類 稱為 超類(superclass)、基類(base class)、父類(parent class)
  • 新類 稱為 子類(subclass)、派生類(derived class)、孩子類(child class)

子類比超類擁有的功能更加豐富。在通過擴充超類定義子類的時候,僅需要指出子類與超類的不同之處。

  • 子類能繼承父類中由public、protected修飾的執行個體域和方法;
  • 當在同一個包下,子類可以繼承父類中的default修飾的執行個體域和方法;
  • 子類不能繼承父類中private修飾的執行個體域和方法。

子類執行個體化時會先在記憶體中開辟其從父類中繼承的所需空間。

示例:

建立People類

public class People {
    private String name;
    private int age;
    private int sex;

    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;
    }

    public int getSex() {
        return sex;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }

    public void run(){
        System.out.println("people run");
    }

    public People(String name, int age, int sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    public People() {
    }
    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }
}

           

建立Student類

public class Student extends People{
    private String studentNum;
    private String schoolName;

    public String getSchoolName() {
        return schoolName;
    }

    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
    }

    public String getStudentNum() {
        return studentNum;
    }

    public void setStudentNum(String studentNum) {
        this.studentNum = studentNum;
    }

    public Student(String studentNum, String schoolName, String name, int age, int sex) {
        super(name, age, sex);
        this.studentNum = studentNum;
        this.schoolName = schoolName;
    }
    public Student(){
    }

    public void run() {
        System.out.println("student run");
    }

    @Override
    public String toString() {
        return "Student{" +
                "studentNum='" + studentNum + '\'' +
                ", schoolName='" + schoolName + '\'' +
                '}' + super.toString();
    }

}

           

示例一:

建立一個Main類

public class Main {
    public static void main(String[] args) {
 		People people = new People("zhangsan",20,1);
        Student student = new Student("111111","xiaoxue","xiaoming",15,1);
        people.run();
        student.run();
    }
}

           

執行結果:

people run
student run
           

結果分析:

在main方法中,通過

People people = new People();

可以建立一個People對象,通過

Student student = new Student();

可以建立一個Studeng對象。Student類繼承了People類,此時對象student在記憶體中有從People類繼承過來的name,age,sex這三個執行個體域(不能直接通路,在類中定義方法時,也不能通路,隻能通過通路器、構造器),同時擁有Student類中的studentNum、schoolName這兩個執行個體域(在類中定義方法時,可以直接通路);對象student可以調用能從People類中繼承來的方法,也可以調用Student類定義的方法;有一點需要注意,在People類中定義了run方法,在Student類中也定義了run方法,此時Student類中的run方法将重寫(覆寫)父類中的run方法,對象student調用run方法将調用Student類中的run方法。

示例二:

在main方法中,寫這麼一段代碼

People people = new Student();

超類、子類之間的繼承、多态

對象people隻能調用People類中的方法,不會報錯。這是因為父類類型對象可以引用子類類型對象,反之

Student student = new People();

,編譯器将報錯。但對象people在記憶體卻開辟一個Student對象的空間,卻隻能使用People類中的方法,而通路不到Student類中的方法。

Main方法:

public class Main {
    public static void main(String[] args) {
        People people = new Student();
        people.setName("zhangsan");
        people.setAge(20);
        people.setSex(1);
        System.out.println(people);
    }
}

           

執行結果:

Student{studentNum='null', schoolName='null'}People{name='zhangsan', age=20, sex=1}
           

結果分析:

在main方法中,如果對象people調用Student中自己的方法,将會報錯。因為它隻能調用People類定義的方法,而toString方法在People類中進行了重寫,在Student類中也進行了重寫,而people對象所引用的是一個Student對象,是以它所調用的toString方法将是被Student類重寫的方法。

示例三:

在main方法中,對上一個示例的對象people進行強制轉換

Student student = (Student)people;

此時對象student将可以調用Student類中的方法,也可以調用People類中的方法。因為對象people實際指向的是Student對象,是以可以将其強制轉化成Student對象。

超類、子類之間的繼承、多态

但是,當對象people指向的是People對象時,再對對象people對象進行Student強制轉換将會報錯。

總結:

簡單來說,

People people = new Student();

就是将對People的描述應用到Student上,該描述不包括Student中自有的部分,是以對象people調用不了。在對它做強制轉換之後,

Student student = (Student)people;

也就是将Student的描述應用到對象people上,因為對象people本身就引用的是Student對象,是以該描述将可以完全描述,對象student也就可以調用到Student類的方法。

Student student = new People();

相當于是用對Student的描述來描述People,因為Student繼承People,故對Student的描述多于對People的描述,故編譯器将會報錯。