2022-07-21 第四組 java之繼承
一、繼承
1.概念
- 繼承的基本思想是,基於已有的類創造新的類。繼承已存在的類就是復用這些類的方法,而且可以增加一些新的方法和字段,使新類能夠適應新的情況,繼承是Java程序設計中一項核心技術,它主要解決的問題是:共性的抽取,實現代碼復用
上圖中,講師類和助教類都繼承員工類,講師類和助教類可以稱為員工類的子類或者派生類,繼承之後,子類可以復用父類的方法和屬性,子類在實現時只關心自己新增加的成員即可。
2.語法
- 定義父類的格式:(一個普通的類定義)
public class 父類名稱{
//…
} - 定義子類的格式:
public class 子類名稱 extends 父類名稱{
//…
}
//Employee.java
public class Employee {
public void method() {
System.out.println("方法執行!");
}
}
//Teacher.java
//定義了一個員工的子類--講師
public class Teacher extends Employee {
}
//Assistant.java
//定義另一個子類---助教
public class Assistant extends Employee {
}
//主方法
public class Demo01Extends {
public static void main(String[] args) {
Teacher teacher = new Teacher();
teacher.method();
Assistant assistant = new Assistant();
assistant.method();
}
}
注意:
- 子類將繼承父類的成員變量和成員方法
- 子類繼承父類之後,需要添加自己特有的成員,體現出與基類的不同
3.父類成員訪問
3.1 子類訪問父類的成員變量
3.1.1 子類和父類中不存在同名的成員變量
public class Base {
int a;
int b;
}
public class Derived extends Base{
int c;
public void method(){
a = 10; //從父類繼承
b = 20; //從父類繼承
c = 30; //訪問自己
}
}
3.1.2 子類和父類中不存在同名的成員變量
public class Base {
int a;
int b;
int c;
}
public class Derived extends Base {
char b; //與父類同名,不同類型
int c; //與父類同名,相同類型
public void method(){
a = 10; //訪問父類繼承
b = 20; //訪問誰的?
c = 30; //訪問誰的?
//d = 40; //編譯器報錯
}
}
注意:
-
如果訪問的成員變量子類中有,則優先訪問子類本身的
-
如果訪問的成員變量子類中無,父類中有,則訪問繼承下來的
-
如果子類與父類中有同名的成員變量,則優先訪問子類自己的,即子類將父類的同名變量隱藏
成員變量的訪問遵循就近原則,自己有就優先訪問自己的
3.2 子類中訪問父類的成員方法
3.2.1 成員方法名字不同
public class Base {
public void method1(){
System.out.println("我是父類方法");
}
}
public class Derived extends Base {
public void method2(){
System.out.println("我是子類方法");
}
public void method(){
method1(); //父類方法
method2(); //子類方法
}
}
3.2.2 成員方法名字相同
public class Base {
public void method1(){
System.out.println("我是父類方法");
}
public void method2(){
System.out.println("我是父類方法");
}
}
public class Derived extends Base {
public void method1(int a){
System.out.println("我是子類方法");
}
public void method2(){
System.out.println("我是子類方法");
}
public void method(){
method1(); //父類方法
method1(10); //子類方法
method2(); //子類方法
}
}
說明:
-
通過子類訪問成員方法,先看子類本身有沒有,如果有訪問自己的,如果沒有,訪問父類的
-
通過子類訪問與父類同名方法時,如果子類和父類方法的參數列表不同則構成重載,根據調用方法傳遞的參數選擇合適的方法訪問
-
如果子類和父類同名方法的原型一致,則只能訪問到子類的
4.重寫(override)
1. 概念
在繼承關係中,方法的名稱不一樣,參數列表也一樣。
2.重載和重寫的區別
重寫(override),方法名稱一樣,參數列表也一樣,覆蓋,覆寫
重載(overload),方法名稱一樣,參數列表不一樣
-
方法重載是一個類中定義了多個方法名相同,而他們的參數的數量不同或數量相同而類型和次序不同,則稱為方法的重載 (overload)。
-
方法重寫是在子類存在方法與父類的方法的名字相同,而且參數的個數與類型一樣,返回值也一樣的方法,就稱為重寫 (override)。
-
方法重載是一個類的多態性表現,而方法重寫是子類與父類的一種多態性表現。
方法重載的要求是參數列表不同。具體包括以下三種情形。
①參數的數量不同。
②參數的類型不同。
③參數的順序不同。
3.方法重寫的注意事項
-
必須保證父子類之間方法的名稱相同,參數列表也相同
@override;寫在方法前面,用來檢測是否是正常的覆蓋重寫 -
子類方法的返回值必須小於等於父類的返回值範圍
前提:object類是所有類的最高父類(祖宗類) -
子類方法的權限必須大於等於父類的權限修飾符
public > protected >(default) >private
備註:(default)不是關鍵字default,而是空
5.super關鍵字
super關鍵字用來訪問父類內容,而this關鍵字用來訪問本類內容,用法也有三種:
- 在本類的成員方法中,訪問本類的成員變量
- 在本類的成員方法中,訪問本類的另一個成員方法
- 在本類的構造方法中訪問另一個構造方法。
第三點注意:this(…)調用也必須是調用方法的第一個語句
this和super兩種構造方法,不能同時使用
6.super和this的內存圖
public class Demo01Extends {
public static void main(String[] args) {
ZI zi = new ZI();
zi.Method();
}
}
-----------------------------
public class Fu {
int num = 10;
}
-----------------------------
public class ZI extends Fu {
int num = 20;
public void Method() {
int num = 30;
System.out.println(num);
System.out.println(this.num);//本類的成員變量
System.out.println(super.num);//父類的成員變量
}
}
7.子類構造方法
構造哪個類的對象,就調用哪個類的構造方法,調用構造方法時先調用基類,在調用子類(即在子類中隱藏super() )
public class Base {
public Base(){
System.out.println("Base()");
}
}
public class Derived extends Base {
public Derived(){
System.out.println("Derived()");
}
}
public class Text {
public static void main(String[] args) {
Derived d = new Derived();
}
}
輸出結果:Base()
Derived()
在子類構造方法中,並沒有寫任何關於基類構造的代碼,但是在構造子類對象時,先執行基類的構造方法,然後執行子類的構造方法
注意:
-
若父類顯示定義無參或者默認的構造方法,在子類構造方法的第一行默認有隱含的super調用,即調用基類的構造方法
-
如果父類的構造方法是帶有參數的,此時編譯器不會給子類生成默認的構造方法,此時需要用戶在子類中顯示定義構造方法,並在子類構造方法中選取合適的父類構造方法調用
-
在子類構造方法中,super(…)調用父類構造時,必須是子類構造方法中的第一條語句
-
super(…)只能在子類的構造方法中出現一次,並不能和this同時出現
8. 執行順序
無繼承關係時的執行順序:
public class Person {
String name;
String gender;
int age;
public Person(String name,String gender,int age){
this.name = name;
this.gender = gender;
this.age = age;
System.out.println("我是構造方法");
}
{
System.out.println("我是實例代碼塊");
}
static {
System.out.println("我是靜態代碼塊");
}
public static void main(String[] args) {
Person p1 = new Person("xiaoHua","男",12);
System.out.println("=====================");
Person p2 = new Person("xiaoHong","女",15);
}
}
執行結果:
說明:
靜態代碼塊先執行,且只執行一次,在類加載階段執行
當有對象創建時,才會執行實例代碼塊,實例代碼塊執行完後,再執行構造方法
有繼承關係時的執行順序:
public class Person {
String name;
String gender;
int age;
public Person(String name,String gender,int age){
this.name = name;
this.gender = gender;
this.age = age;
System.out.println("person的構造方法");
}
{
System.out.println("person的實例代碼塊");
}
static {
System.out.println("person的靜態代碼塊");
}
}
public class Student extends Person{
public Student(String name, String gender, int age) {
super(name, gender, age);
System.out.println("student的構造方法");
}
{
System.out.println("student的實例代碼塊");
}
static {
System.out.println("student的靜態代碼塊");
}
}
public class Text {
public static void main(String[] args) {
Student s1 = new Student("張三","男",35);
System.out.println("=====================");
Student s2 = new Student("李四","男",30);
}
}
執行結果:
結論:
-
父類靜態代碼塊優先子類靜態代碼塊執行,都是最早執行的
-
父類實例代碼塊和父類構造方法緊接着執行
-
子類的實例代碼塊和子類構造方法在接着執行
-
第二次實例化對象時,父類和子類的靜態代碼塊都不會在執行
9. 繼承方式
Java中只支持以下幾種方式:
注意:Java中不支持多支持
10. final關鍵字
final關鍵字可以用來修飾變量,成員方法以及類。
1.修飾變量或字段,表示常量(即不能修改)
final int a = 10;
a = 20;//編譯報錯
2.修飾類,表示類不能繼承
final public class Person{
}
public class Student extends Person{
}//編譯報錯
3.修飾方法,表示方法不能被重寫(後續在介紹)