Java官方筆記6繼承

繼承

Java只有單繼承,最頂級的父類是Object。

子類會繼承父類的fields和methods,而不會繼承constructors,因爲constructors不屬於methods,但是子類可以通過super調用父類的constructor。

子類繼承父類的範圍是:public、protected、package-private

隱式轉換,子類轉父類(只有1個爸爸):

Object obj = new MountainBike();

顯示轉換,父類轉子類(有多個子女,所以要明確指定):

MountainBike myBike = (MountainBike)obj;

類有field,而接口沒有,所以在多繼承時就有問題:如果多個類有相同的field,那麼子類將不知道用哪一個,而接口不存在這個問題。Java不支持繼承多個類,但是可以實現多個接口。

重載

子類的方法跟父類有完全相同的簽名和返回類型(也可以是子類),將會覆蓋父類方法Override

如果子類定義了1個static方法,跟父類完全相同,那麼父類方法會被隱藏Hide

Override和Hide是不同的:

public class Animal {
    public static void testClassMethod() {
        System.out.println("The static method in Animal");
    }
    public void testInstanceMethod() {
        System.out.println("The instance method in Animal");
    }
}
public class Cat extends Animal {
    public static void testClassMethod() {
        System.out.println("The static method in Cat");
    }
    public void testInstanceMethod() {
        System.out.println("The instance method in Cat");
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        Animal myAnimal = myCat;  // 隱式轉換
        Animal.testClassMethod();  // 調的父類
        myAnimal.testInstanceMethod();  // 父類對象引用,還是調的子類
    }
}
The static method in Animal
The instance method in Cat

Override只會調子類方法,而Hide取決於調用方是父還是子,比如這裏的myCat,隱式轉換爲父類Animal後,會調父類的static方法,而調的實例方法卻是子類的。(如果不是隱式轉換,而是直接給父類實例化,那肯定還是調父類方法)

類instance方法優先於接口default方法:

public class Horse {
    public String identifyMyself() {
        return "I am a horse.";
    }
}

public interface Flyer {
    default public String identifyMyself() {
        return "I am able to fly.";
    }
}

public interface Mythical {
    default public String identifyMyself() {
        return "I am a mythical creature.";
    }
}

public class Pegasus extends Horse implements Flyer, Mythical {
    public static void main(String... args) {
        Pegasus myApp = new Pegasus();
        System.out.println(myApp.identifyMyself());
    }
}

輸出爲I am a horse.

Override的優先:

public interface Animal {
    default public String identifyMyself() {
        return "I am an animal.";
    }
}

public interface EggLayer extends Animal {
    default public String identifyMyself() {
        return "I am able to lay eggs.";
    }
}

public interface FireBreather extends Animal { }

public class Dragon implements EggLayer, FireBreather {
    public static void main (String... args) {
        Dragon myApp = new Dragon();
        System.out.println(myApp.identifyMyself());
    }
}

輸出爲I am able to lay eggs

如果實現多接口,有同名的,需要顯示指定調用方:

public interface OperateCar {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Implementation
    }
}

public interface FlyCar {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Implementation
    }
}
public class FlyingCar implements OperateCar, FlyCar {
    // ...
    public int startEngine(EncryptedKey key) {
        FlyCar.super.startEngine(key);  // 顯示指定,並且使用super
        OperateCar.super.startEngine(key);  
    }
}

總結下,如果子類方法簽名+return跟父類方法一樣,有以下4種情況:

注意compile-time error,static方法不能和instance方法一樣,因爲它們是不同級別的。

多態

MountainBike和RoadBike都繼承Bicycle,雖然都有printDescription,但它們有多樣的形態:

public class MountainBike extends Bicycle {
    private String suspension;

    public MountainBike(
               int startCadence,
               int startSpeed,
               int startGear,
               String suspensionType){
        super(startCadence,
              startSpeed,
              startGear);
        this.setSuspension(suspensionType);
    }

    public String getSuspension(){
      return this.suspension;
    }

    public void setSuspension(String suspensionType) {
        this.suspension = suspensionType;
    }

    public void printDescription() {
        super.printDescription();
        System.out.println("The " + "MountainBike has a" +
            getSuspension() + " suspension.");
    }
} 
public class RoadBike extends Bicycle{
    // In millimeters (mm)
    private int tireWidth;

    public RoadBike(int startCadence,
                    int startSpeed,
                    int startGear,
                    int newTireWidth){
        super(startCadence,
              startSpeed,
              startGear);
        this.setTireWidth(newTireWidth);
    }

    public int getTireWidth(){
      return this.tireWidth;
    }

    public void setTireWidth(int newTireWidth){
        this.tireWidth = newTireWidth;
    }

    public void printDescription(){
        super.printDescription();
        System.out.println("The RoadBike" + " has " + getTireWidth() +
            " MM tires.");
    }
}

所謂的虛擬方法調用,名字很高大上,其實質就是,子類重載了父類方法,在調用子類實例方法時,先調子類實現:

注意,子類的field如果和父類的一樣,那麼父類的field會被hide,即使type不一樣。如果要使用父類的field,需要關鍵字super。同名fileld是不好的設計,應該儘量避免。

super關鍵字

public class Superclass {

    public void printMethod() {
        System.out.println("Printed in Superclass.");
    }
}
public class Subclass extends Superclass {

    // overrides printMethod in Superclass
    public void printMethod() {
        super.printMethod();
        System.out.println("Printed in Subclass");
    }
    public static void main(String[] args) {
        Subclass s = new Subclass();
        s.printMethod();    
    }
}

在子類constructor中,如果沒有顯式super,那麼會調用默認的super()

Object

Java中的所有類,都終極繼承了Object。(繼承鏈的頂端)

toString()

System.out.println(firstBook.toString());

equals()

public class Book {
    String ISBN;
    
    public String getISBN() { 
        return ISBN;
    }
    
    public boolean equals(Object obj) {
        if (obj instanceof Book)
            return ISBN.equals((Book)obj.getISBN()); 
        else
            return false;
    }
}

hashCode()

如果兩個對象相等,那麼它們的hashCode一定相等。重寫equals(),必須重寫hashCode()

getClass()

void printClassName(Object obj) {
    System.out.println("The object's" + " class is " +
        obj.getClass().getSimpleName());
}

clone()

aCloneableObject.clone();

finalize()

垃圾回收時調用。它的調用時機是不確定的,不要使用它來做邏輯。

抽象

abstract class,抽象類,不能被實例化,但是可以繼承。

abstract void moveTo(double deltaX, double deltaY);

如果抽象類有method,那麼也必須是abstract:

public abstract class GraphicObject {
   // declare fields
   // declare nonabstract methods
   abstract void draw();
}

子類必須抽象類的所有方法,否則子類也必須是abstract。

抽象類:(not static、final) field,(public、protected、private) method

接口:public static final field,public method

Java中,抽象類的例子是AbstractMap、接口的例子是HashMap實現的Serializable, Cloneable, and Map<K, V>接口。

image-20230602232643026

如果類沒有實現接口中的所有方法,可以定義爲abstract,然後由子類來實現剩餘的全部方法:

abstract class X implements Y {
  // implements all but one method of Y
}

class XX extends X {
  // implements the remaining method in Y
}

X沒有實現全部方法,所以是abstract,子類XX實現剩餘全部方法。

參考資料:

Inheritance https://dev.java/learn/inheritance/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章