Java繼承和多態(tài)


Java繼承和多態(tài)

繼承

定義

繼承就是利用現(xiàn)有類創(chuàng)建新類的過程,現(xiàn)有的類稱為 父類(基類),新類稱為 子類(派生類)。比如現(xiàn)實中:兒子繼承了父親遺產(chǎn)一樣。面向?qū)ο蟪绦蛟O(shè)計中的繼承,就是代碼重用。
Java中所有的類都繼承自 Object 這個父類。

實現(xiàn)

在Java中實現(xiàn)繼承需要使用到extends關(guān)鍵字;

[訪問修飾符] class 派生類名 extends 基類名 {
        成員列表
    }

如:

class Student extends Person
{
    ……
}

訪問修飾符 請參看之前章節(jié)的內(nèi)容。

例子

例:

定義抽象類:Person。

public abstract class Person {  // 抽象類
    private String name;  // 私有變量
    
    public String getName() {  // Getter方法
        return name;
    }
    public void setName(String name) {  //Setter方法
        this.name = name;
    }
        
    public Person(String name) {  // 構(gòu)造函數(shù),用于初始化name
        super();
        this.name = name;
    }
    public abstract String getDesc();  // 抽象類中的抽象方法。  只有聲明,沒有具體實現(xiàn)。
  
      public String toString(){      // toString方法覆蓋了Object類的toString方法
         return name + getDesc();
      }
}

public class Student extends Person {  // 繼承類
    private String major; // 新增加的數(shù)據(jù)    
    
    public String getMajor() {
        return major;
    }
    
    public void setMajor(String major) {
        this.major = major;
    }    
    
    public Student(String name,String major) { // 構(gòu)造函數(shù)用于初始化
        super(name);   // 調(diào)用超類構(gòu)造函數(shù)
        this.major = major;
    }
    
    @Override
    public String getDesc() {  // 必須實現(xiàn)超類中的抽象方法
        // TODO Auto-generated method stub
        return " : a student, major is " + major;
    }

繼承的作用

  • 當今軟件設(shè)計的特征
    軟件規(guī)模越來越大
    軟件設(shè)計者越來越多
    軟件設(shè)計分工越來越細
  • 引入繼承,實現(xiàn)了代碼重用;
  • 引入繼承,實現(xiàn)了遞增式的程序設(shè)計。
  • 繼承是能自動傳播代碼和重用代碼的有力工具;
  • 繼承能夠在某些比較一般的類的基礎(chǔ)上建造、建立和擴充新類;
  • 能減少代碼和數(shù)據(jù)的重復(fù)冗余度,并通過增強一致性來減少模塊間的接口和界面,從而增強了程序的可維護性;
  • 能清晰地體現(xiàn)出類與類之間的層次結(jié)構(gòu)關(guān)系。

注意事項

  • 繼承是單方向的,即派生類可以繼承和訪問基類中的成員,但基類則無法訪問派生類中的成員; 父類不能訪問子類方法
  • 在Java中只允許 單一繼承 方式,即一個派生類只能繼承于一個基類,而不能象C++中派生類繼承于多個基類的多重繼承方式。

繼承中的構(gòu)造方法

  • 父類中的構(gòu)造方法可以被重載,但不能被子類繼承,即便它是public的;
  • 父類的構(gòu)造方法負責初始化屬于它的成員變量,而子類的構(gòu)造方法則只需考慮屬于自己的成員變量,不必去關(guān)注父類的情況。
  • 當實例化子類的對象時,必須先執(zhí)行父類的構(gòu)造方法,然后再執(zhí)行子類的構(gòu)造方法;
  • 如果父類還有更上級的父類,就會先調(diào)用最高父類的構(gòu)造方法,再逐個依次地將所有繼承關(guān)系的父類構(gòu)造方法全部執(zhí)行;
  • 如果父類的構(gòu)造方法執(zhí)行失敗,那么子類的對象也將無法實例化。

class ParentClass {  //定義父類
  public ParentClass() {  //構(gòu)造方法
    System.out.println("這是父類的構(gòu)造方法。");
  }
}

class ChildClass extends ParentClass {  //子類繼承于父類
  public ChildClass() {  //構(gòu)造方法
    System.out.println("這是子類的構(gòu)造方法。");
  }
}

public class ConstructorTest {  //該類用于容納main方法
  public static void main(String[] args) {
    ChildClass cc = new ChildClass();  //實例化子類對象
  }
}

super

如果子類需要調(diào)用父類的方法或者屬性怎么辦?

  • 在子類的構(gòu)造方法中,super關(guān)鍵字可以顯式地調(diào)用父類的構(gòu)造方法,用于將參數(shù)傳遞給它;需要注意的是: 該語句必須是子類構(gòu)造方法的第一條語句

如:

class Point  //定義"點"類
{
  protected float mX, mY;  //x軸坐標和y軸坐標

  public Point(float x, float y)  //構(gòu)造方法
  {
    mX = x;
    mY = y;
  }
  ……
}

class Circle extends Point  //定義"圓"類繼承于"點"類
{
  protected float mRadius;    //半徑

  public Circle(float x, float y, float r)  //構(gòu)造方法
  {
    super(x, y);  //顯式調(diào)用父類構(gòu)造方法,必須是第一條語句
    mRadius = r;
  }
  ……
}
  • 如果父類和子類中有同名成員,在子類中默認訪問是屬于自己的那一個成員;super關(guān)鍵字可以明確地指定要訪問父類中的成員;但前提條件是:父類中的該成員不是private的

多態(tài)

方法覆蓋

定義
  • 在類的繼承體系結(jié)構(gòu)中,如果子類中出現(xiàn)了與父類中有同原型的方法,那么認為子類中的方法覆蓋了父類中的方法(也稱為方法重寫);
  • 通過子類的實例調(diào)用被覆蓋的方法時,將總是調(diào)用子類中的方法,而父類中的方法將被隱藏。

如:

/*如果不但名稱相同,而且連方法原型也完全相同的話,則構(gòu)成方法覆蓋*/
class ParentClass {  //定義父類
  public void fun() {
    System.out.println("這是父類中的方法。");
  }
}

class ChildClass extends ParentClass {//子類繼承于父類
  public void fun() {  //子類覆蓋父類中的方法
    System.out.println("這是子類中的方法。");
  }
}

class OverriddenTest {  //用于容納main方法
  public static void main(String[] args) {
    ParentClass parObj = new ParentClass();
    parObj.fun();  //父類的實例調(diào)用此方法

    ChildClass chiObj = new ChildClass();
    chiObj.fun();  //子類的實例調(diào)用此方法
  }
}
方法覆蓋的注意事項
  • 子類中重寫的方法,其訪問權(quán)限不能比父類中被重寫方法的訪問權(quán)限更低
  • 在子類中重寫方法時要保持方法的簽名與父類中方法的簽名一致

引用轉(zhuǎn)型

  • 基類(父類)的引用可以指向派生類(子類)的對象。

如:

BaseClass obj = new DerivedClass();
  • 如果存在方法覆蓋,那么將會調(diào)用其派生類中的方法

如:

class Shapes {  //基本形狀類
  public void draw() {  //繪圖的方法
    System.out.println("繪制了一個基本形狀。");
  }
}
class Circle extends Shapes {  //圓形類繼承于基本形狀類
  public void draw() {  //覆蓋父類的繪圖方法
    System.out.println("繪制了一個圓形。");
  }
} 
class Square extends Shapes {  //正方形類繼承與基本形狀類
  public void draw() {  //覆蓋父類的繪圖方法
    System.out.println("繪制了一個正方形。");
  }
}
public class polymorphismDemo {
  public static void main(String[] args) {
    Shapes obj = new Shapes();  //父類的引用指向父類的實例
    obj.draw();                 //調(diào)用繪圖方法
    obj = new Circle();         //父類的引用指向子類的實例
    obj.draw();                 //調(diào)用繪圖方法
    obj = new Square();         //父類的引用指向子類的實例
    obj.draw();                 //調(diào)用繪圖方法
  }
}

多態(tài)

在Java中,使用父類的引用,調(diào)用同一個方法,卻可以得到不同的調(diào)用結(jié)果,這就是多態(tài)。即: 同一函數(shù),多種形態(tài)。
實際上多態(tài)包括 動態(tài)多態(tài)靜態(tài)多態(tài)

靜態(tài)多態(tài)
  • 靜態(tài)多態(tài)也稱為編譯時多態(tài),即在編譯時決定調(diào)用哪個方法;
  • 靜態(tài)多態(tài)一般是指方法重載;
  • 只要構(gòu)成了方法重載,就可以認為形成了靜態(tài)多態(tài)的條件;
  • 靜態(tài)多態(tài)與是否發(fā)生繼承沒有必然聯(lián)系。
動態(tài)多態(tài)

動態(tài)多態(tài)也稱為運行時多態(tài),即在運行時才能確定調(diào)用哪個方法。
形成動態(tài)多態(tài)必須具體以下條件:

  • 必須要有繼承的情況存在;
  • 在繼承中必須要有方法覆蓋;
  • 必須由基類的引用指向派生類的實例,并且通過基類的引用調(diào)用被覆蓋的方法;

由上述條件可以看出,繼承是實現(xiàn)動態(tài)多態(tài)的首要前提。

抽象

抽象方法

基類無法(或者沒有必要)提供被覆蓋方法的具體實現(xiàn),那么就可以將這個方法定義為 抽象方法。

[訪問權(quán)限] abstract 返回值類型 方法名(參數(shù)列表){
}

如:

public abstract void draw(){
}
抽象類

如果某個類包含抽象方法,那么這個類就必須定義成 抽象類。

[訪問權(quán)限] abstract class 類名{
    成員列表
}

如:

public abstract class Shapes{
    public abstract void draw();
}
抽象類的注意事項
  • 抽象類不可以直接實例化,只可以用來繼承;
  • 抽象類的派生子類應(yīng)該提供對其所有抽象方法的具體實現(xiàn);
  • 如果抽象類的派生子類沒有實現(xiàn)其中的所有抽象方法,那么該派生子類仍然是抽象類,只能用于繼承,而不能實例化;
  • 抽象類中也可以包含有非抽象的方法;
  • 構(gòu)造方法和靜態(tài)方法不可以修飾為abstract。

如:

abstract class Shapes {  //基本形狀類,抽象類
    public abstract void draw();  //繪圖方法,抽象方法
}
class Circle extends Shapes {  //圓形類繼承于基本形狀類
    public void draw() {  //實現(xiàn)抽象父類的抽象繪圖方法
        System.out.println("繪制了一個圓形。");
    }
}
class Square extends Shapes {  //正方形類繼承與基本形狀類
    public void draw() {  //實現(xiàn)抽象父類的抽象繪圖方法
        System.out.println("繪制了一個正方形。");
    }
}
public class abstractDemo {  //該類用于容納main方法
    public static void main(String[] args) {
        Shapes obj;
        obj = new Circle();         //父類的引用指向子類的實例
        obj.draw();                 //調(diào)用繪圖方法
        obj = new Square();         //父類的引用指向子類的實例
        obj.draw();                 //調(diào)用繪圖方法
    }
}

接口

接口定義

如果某個類中所有的方法都是 抽象方法,那么可以考慮將該類定義為接口。

[訪問權(quán)限] interface 接口名{
    成員列表
}

如:

public interface IMyInterface{
    public void doIt();
}
實現(xiàn)接口

接口只能用于實現(xiàn),不能實例化(new)。

[訪問權(quán)限] class 類名 implements 接口名 {
    成員列表
}

如:

public class MyClass implements IMyInterface {
    public void doIt(){
    }
}
接口的注意事項
  • 接口中不能定義非抽象方法,也就是說接口中不能包含有函數(shù)實體。
    接口中的所有方法都默認為抽象方法,無需在每個方法前加abstract關(guān)鍵字。
  • 接口的實現(xiàn)類應(yīng)該提供對接口中所有抽象方法的具體實現(xiàn),否則將成為抽象類。
    與抽象類和它的繼承類相似,也可以使用接口的引用指向其實現(xiàn)類的對象,從而達到動態(tài)多態(tài)的效果。
  • Java只支持單繼承,而不能象C++那樣可以多重繼承,接口正是為了彌補這一點。
  • Java中還允許一個接口繼承于另一個接口,即由父接口派生出子接口。

如:

public interface 子接口名 extends 父接口名 {
    成員列表
}

final關(guān)鍵字

final修飾變量

如果將某個變量修飾為final,那么該變量就成為 常量
如:

final double PI = 3.14159;

☆ 常量在聲明時必須初始化。

final修飾方法

如果將某個成員方法修飾為final,則意味著該方法 不能被子類覆蓋
如:

public final void fun() {
    ……
}
//如果在派生類中出現(xiàn)同原型的方法,將會報錯。
final修飾類

如果將某個類修飾為final,則說明該類 無法被繼承
如:

public final class MyClass {
    ……
}
//任何類想繼承于MyClass類都將報錯。

類和類之間的關(guān)系

  • 有——>has
    汽車有輪子。一般來說這種關(guān)系對應(yīng)的是 屬性。

  • 是——>is
    圓形是個形狀。一般來說這種關(guān)系對應(yīng)的是 方法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 1,268評論 0 5
  • 繼承和多態(tài) 1. 繼承的優(yōu)缺點 優(yōu)點:(1)子類可以靈活地改變父類中的已有方法;(2)能夠最大限度的實現(xiàn)代碼重用。...
    MinoyJet閱讀 724評論 0 0
  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,241評論 0 62
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,623評論 18 399
  • 昨天,我的大學(xué)室友給我發(fā)來一屏幕的微信語音 大致的意思是,她有一個又丑又丑的同學(xué),通過整容把自己變成白富美,還有一...
    呼啦來了閱讀 570評論 0 0

友情鏈接更多精彩內(nèi)容