1. 程式人生 > >java 面向物件三大特性之一:繼承

java 面向物件三大特性之一:繼承

      前言:

   繼承,既是對現有類的複用。如果子類繼承了父類,那麼子類就擁有了父類的能力了。除此之外,子類還能加入自己新加入的方法,功能,或是重新定義從父類繼承的某項功能。這樣,就可以在現有的功能上開發新的功能,這樣能大大減少開發的週期.

|繼承的優點|

 現在我們來構建一個Cat的類

package Test.practice.thinking_in_java.extend_test;

/**
 * @Author 7aY
 * @Description: TODO()
 * @Date :Create in 13:202018/3/12
 */

/**
 * 貓類
 */
public class Cat {
    private int age;//年齡
    private int weigth;//體重
    private String name;//名字

    public int getAge() {
        return age;
    }
    public Cat(int age,int weigth,String name){
        this.age=age;
        this.weigth=weigth;
        this.name=name;

    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getWeigth() {
        return weigth;
    }

    public void setWeigth(int weigth) {
        this.weigth = weigth;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public void printMessage(){
        System.out.println("name:"+getName()+" weigth:"+getWeigth()+"kg  age:"+getAge());
    }
    public  Cat(){}

}

這個Cat類包含體重 名字 身高等資訊,但現在我想要在這個Cat的基礎上建立一個EgyptianCat的類,我要重新把之前的程式碼重新再寫一次然後再新增新的東西下去嗎?很顯然這會十分的麻煩且無用,所以這時候extend 這個關鍵字發揮了他的用處了

public class EgyptianCat extends Cat {
    private  String color;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
    public EgyptianCat(int height,int weigth,String name,String color){
        super(height,weigth,name);
        this.color=color;
    }

    @Override
    public void printMessage() {

        System.out.println("name:"+getName()+" weigth:"+getWeigth()+"kg  age:"+getAge()+"color:"+getColor());
    }
}

和Cat相比,EgyptianCat就多了個一個私用屬性color,通過extend繼承,我們的類構建可以簡潔很多,並且可以在繼承的基礎上重新構建一個屬於我們新類的方法,這種方法叫做重寫方法(PS:重寫方法會呼叫上一層繼承的被重寫方法)

這裡我們重寫了父類的printMessage()方法,在列印資訊中新加入了color屬性

現在我們來new下父類和子類並且呼叫他們的printMessage方法檢視下結果

 public static void main(String[] args) {
        Cat cat = new Cat(2,10,"jay");
        cat.printMessage();
        EgyptianCat egyptianCat = new EgyptianCat(3,5,"lois","black");
        egyptianCat.printMessage();

    }

輸出結果為:

name:jay weigth:10kg  age:2
name:lois weigth:5kg  age:3 color:black

|成員的繼承|

如果子類繼承了父類,則:

1.子類繼承父類的所有public與protect成員,無論子類是否與父類在同一個包中;

2.如果子類與父類在同一個包中,那麼子類也會繼承父類包訪問許可權

3.子類不能繼承父類的私有成員,但是子類可以通過父類的public或protect方法間接訪問父類的私有成員

package Test.practice.thinking_in_java.extend_test;

/**
 * @Author 7aY
 * @Description: TODO()
 * @Date :Create in 22:212018/3/13
 */
public class SuperClass {
    public int public_value;
    protected  int protect_value;
    private int private_value;
    public SuperClass(){
        public_value=1;
        protect_value=2;
    }

    public int getPrivate_value() {
        return private_value;
    }

    public void setPrivate_value(int private_value) {
        this.private_value = private_value;
    }
}

在SuperClass這個類中我們宣告三種訪問許可權的變數,讓我們看下他的子類是怎麼繼承成員變數的

package Test.practice.thinking_in_java.extend_test;

/**
 * @Author 7aY
 * @Description: TODO()
 * @Date :Create in 22:242018/3/13
 */
public class ExtendClass extends SuperClass {


    public void printMessage() {
        System.out.println("public value:"+public_value);
        System.out.println("protect value"+protect_value);
        // System.out.println("private value"+private_value); 並不能直接訪問私有屬性
        System.out.println("private value:"+getPrivate_value());
    }

    public static void main(String[] args) {
        ExtendClass extendClass = new ExtendClass();
        extendClass.setPrivate_value(3);
        extendClass.printMessage();

    }
}

我們新建立了一個ExtendClass類,其中聲明瞭一個printMessage打印出成員變數的資訊,讓我們看下結果吧

public value:1
protect value2
private value:3

結果說明,子類能直接繼承父類的public和protect成員變數,但並不能直接繼承私有變數,但能通過setter和getter方法來訪問private變數

|繼承的向上轉型和向下轉型|

如果子類繼承了父類,那麼我們可以認為子類是父類的其中一種,是父類的特殊拓展版,例如Cat類繼承於Animal類,那麼我們可以把Cat看做為Animal,Cat具有Animal的所有特徵,但並不能把Animal看做為Cat,因為並不是所有的Animal都是Cat.

 在Java中,我們可以把父類的引用賦值給子類的物件,然後通過父類的引用來進行操作,這種操作被稱為向上轉型,但是,子類的新增方法並不能進行使用和操作。我們不能把子類的引用賦值給父類的物件,就像前面所說的,可以把Cat看做為Animal,Cat具有Animal的所有特徵,但並不能把Animal看做為Cat,因為並不是所有的Animal都是Cat.

package Test.practice.thinking_in_java.extend_test;

/**
 * @Author 7aY
 * @Description: TODO()
 * @Date :Create in 22:432018/3/13
 */
public class Animal {
    public void walk(){
        System.out.println("Animal walk!!");
    }
    public void sleep(){
        System.out.println("Animal sleep!!");
    }
    public void eat(){
        System.out.println("Animal eat!!");
    }
}

我們現在建立一個Animal類,然後我們再建立一個Cat類繼承於Animal類

package Test.practice.thinking_in_java.extend_test;

/**
 * @Author 7aY
 * @Description: TODO()
 * @Date :Create in 13:202018/3/12
 */

/**
 * 貓類
 */
public class Cat extends Animal {
    private int age;//年齡
    private int weigth;//體重
    private String name;//名字

    public int getAge() {
        return age;
    }
    public Cat(int age,int weigth,String name){
        this.age=age;
        this.weigth=weigth;
        this.name=name;

    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getWeigth() {
        return weigth;
    }

    public void setWeigth(int weigth) {
        this.weigth = weigth;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public void printMessage(){
        System.out.println("name:"+getName()+" weigth:"+getWeigth()+"kg  age:"+getAge());
    }
    public  Cat(){}
     public void  Meow(){
         System.out.println("meow!!!!");
     }
}

其中Cat類中新增了一個Meow的貓叫方法

現在我們來測試一下:

package Test.practice.thinking_in_java.extend_test;

/**
 * @Author 7aY
 * @Description: TODO()
 * @Date :Create in 22:492018/3/13
 */
public class Test {
    public static void main(String[] args) {
        Animal cat = new Cat();
        cat.eat();
        cat.sleep();
        cat.walk();
        //但是不能呼叫Meow這個方法,現在我們把cat引用轉為Cat
        cat=(Cat) cat;
        ((Cat) cat).Meow();
        //Cat animal = new Animal(); 編譯器報錯,並不能向下轉型!

    }
}

結果:

Animal eat!!
Animal sleep!!
Animal walk!!
meow!!!!

正如之前所說的一樣,父類引用指向子類物件不能使用子類自己新增的方法,而且如果向下轉型的話編譯器會報錯,那麼向下轉型有什麼作用呢?之後我們會提到.

|多型的實現|

 現在我們要編寫一個動物園類,檢查傳入的動物是什麼動物

package Test.practice.thinking_in_java.extend_test;

/**
 * @Author 7aY
 * @Description: TODO()
 * @Date :Create in 0:212018/3/15
 */
public class Zoo {
    //動物園檢查動物
    public void check(Animal animal){
        System.out.println("this is animal!");

    }
    public void check(Cat cat){
        System.out.println("this is cat!");

    }
    public void check(EgyptianCat egyptianCat){
        System.out.println("this is egyptianCat!");

    }

    public static void main(String[] args) {
        Zoo zoo = new Zoo();
        Animal animal = new Animal();
        Cat cat = new Cat();
        EgyptianCat egyptianCat = new EgyptianCat();
        zoo.check(animal);
        zoo.check(cat);
        zoo.check(egyptianCat);
    }
}

結果:

this is animal!
this is cat!
this is egyptianCat!

以上的程式碼是check方法的過載,看上去沒有任何問題.但只要我們稍加修改,用到上面的向上轉型,結果則會出人意料

  public static void main(String[] args) {
        Zoo zoo = new Zoo();
        Animal animal = new Animal();
        Cat cat = new Cat();
        Animal egyptianCat = new EgyptianCat();
        zoo.check(animal);
        zoo.check(cat);
        zoo.check(egyptianCat);
    }
}

輸出結果:

this is animal!
this is cat!
this is animal!

這是因為方法過載是靜態的,傳入引數型別是看型別的引用,前面cat的引用型別是Animal,所有編譯器自動把cat傳到Animal的過載方法中。

現在我們稍加修改

public class Zoo {
    //動物園檢查動物

    public void check(Animal animal){
        animal.printInfo();
    }

    public static void main(String[] args) {
        Zoo zoo = new Zoo();
        Animal animal = new Animal();
        Cat cat = new Cat();
        Animal egyptianCat = new EgyptianCat();
        zoo.check(animal);
        zoo.check(cat);
        zoo.check(egyptianCat);
    }
}

結果為:

this is Animal
this is cat
this is EgyptianCat

這裡說明一下,Animal 、Cat、EgyptianCat類中都有一個printInfo方法打印出自身的資訊

從結果可以看出,雖然是向上轉型,但是仍能準確輸出類的資訊,並且在Zoo類中並不需要過載方法,試想一下每當有一個新的類出現就過載一次,那麼這個Zoo類的過載方法是不是太多了,以後管理起來也不方便,但使用多型的話,這需要在子類中重寫方法即可,十分的方便。

【總結】

 使用繼承這個關鍵字extend 能減少我們程式碼編寫的工作量,但在重寫的時候要注意,例如重寫,類的變數繼承等

因為有了繼承,使得程式碼的複用有了千變萬化的機會