java學習day09——繼承、抽象

繼承

在這裏插入圖片描述
在繼承的關係中,“子類就是一個父類”。也就是說,子類可以被當做父類看待。
例如父類是員工,子類是講師,那麼“講師就是一個員工”。這樣的關係:is-a。

定義父類的格式:(一個普通的定義)

public class 父類名稱{
// …
}

定義子類的格式:

public class 子類名稱 extends 父類名稱{
// …
}

//定義一個父類:員工
public class Employee {
    public void method(){
        System.out.println("方法執行!");
    }
}
// 定義了一個員工的子類:講師
public class Teacher extends Employee{
}
// 定義了一個員工的子類:助教
public class Assistant extends Employee {
}
public class Demo01Extends {
    public static void main(String[] args) {
        // 創建了一個子類對象
        Teacher teacher = new Teacher();
        // Teacher類當中雖然什麼都沒寫,但是會繼承來自父類的method方法
        teacher.method();

        //創建另一個子類助教的對象
        Assistant assistance = new Assistant();
        assistance.method();
    }
}

繼承中成員變量的訪問特點

public class Fu {
    int numFu = 10;
    int num = 100;//跟子類中變量重名

    public void methodFu(){
        // 使用的是本類當中的,不會向下找子類的
        System.out.println(num);
    }
}
public class Zi extends Fu{
    int numZi = 20;
    int num = 200;

    public void methodZi(){
        // 因爲本類當中有num,所以這裏用的是本類的num
        System.out.println(num);
    }
}

在父子類的繼承關係當中,如果成員變量重名,則創建子類對象時,訪問有兩種方式:

  1. 直接通過子類對象訪問成員變量:
    等號左邊是誰,就優先用誰,沒有則向上找。
  2. 間接通過成員方法訪問成員變量:
    該方法屬於誰,就優先用誰,沒有則向上找。
public class Demo01ExtendsField {
    public static void main(String[] args) {
        Fu fu = new Fu();//創建父類對象
        System.out.println(fu.numFu);//只能使用父類的東西,沒有任何子類內容

        Zi zi = new Zi();

        System.out.println(zi.numFu);// 10
        System.out.println(zi.numZi);// 20

        System.out.println(zi.num); // 優先子類,200

        // 這個方法是子類的,就優先用子類的,沒有再向上找
        zi.methodZi(); // 200
        // 這個方法是在父類當中定義的
        zi.methodFu(); // 100
    }
}

區分子類方法中重名的三種變量

局部變量: 直接寫
本類的成員變量: this.成員變量名
父類的成員變量: super.成員變量名

// 父類
public class Fu {
    int num = 10;
}
// 子類
public class Zi extends Fu {
    int num = 20;

    public void method() {
        int num = 30;//局部變量
        System.out.println(num);//30,局部變量
        System.out.println(this.num);//20,本類的成員變量
        System.out.println(super.num);//10,父類的成員變量
    }
}

繼承中成員方法的訪問特點

在父子類的繼承關係中,創建子類對象,訪問成員方法的規則
創建的對象是誰,就優先用誰,如果沒有則向上找
【注意事項】
無論是成員方法還是成員變量,如果沒有都是向上找父類,絕對不會向下找子類的。

public class Fu {
    public void methodFu(){
        System.out.println("父類方法執行");
    }
    public void method(){
        System.out.println("父類重名方法執行");
    }
}
public class Zi extends Fu {
    public void methodZi(){
        System.out.println("子類方法執行");
    }
    public void method(){
        System.out.println("子類重名方法執行");
    }
}
public class Demo01ExtendsMethod {
    public static void main(String[] args) {
        Zi zi = new Zi();

        zi.methodFu(); //父類方法執行
        zi.methodZi(); //子類方法執行

        // 創建的是new了的子類對象,所以優先用子類方法
        zi.method(); //子類重名方法執行
    }
}

繼承中方法的覆蓋重寫

重寫(Override)概念

在繼承關係當中,方法的名稱一樣,參數列表也一樣

重寫(Override):方法的名稱一樣,參數列表【也一樣】。 覆蓋、覆寫。
重載(Overload):方法的名稱一樣,參數列表【不一樣】。

方法的覆蓋重寫特點

創建的是子類對象,則優先用子類方法。

方法覆蓋重寫的注意事項:

  1. 必須保證父子類方法的名稱相同,參數列表也相同
    @override:寫在方法前面,用來檢測是不是有效的正確覆蓋重寫(起到安全檢測的作用)
    這個註解就算不寫,只要滿足要求,也是正確的覆蓋重寫
  2. 子類方法的返回值必須【小於等於】父類方法的返回值範圍
    java.lang.Object類是所有類的公共最高父類(祖宗類),java.lang.String就是Object的子類
  3. 子類方法的權限必須【大於等於】父類方法的權限修飾符。
    public > protected > (default) > private
    備註:(default)不是關鍵字default,而是什麼都不寫。留空。

public\protected\default\private的區別

private : 在同一類內可見。使用對象:變量、方法。 注意:不能修飾類(外部類)
default (即缺省,什麼也不寫,不使用任何關鍵字): 在同一包內可見,不使用任何修飾符。使用對象:類、接口、變量、方法。
protected : 對同一包內的類和所有子類可見。使用對象:變量、方法。 注意:不能修飾類(外部類)。
public : 對所有類可見。使用對象:類、接口、變量、方法
在這裏插入圖片描述

public class Fu {
    private Object method(){
        return null;
    }
}
public class Zi extends Fu {
    @Override
    public String method(){
        return null;
    }
}

覆蓋重寫的應用

在這裏插入圖片描述

// 父類:老手機
public class Phone {
    public void call(){
        System.out.println("打電話");
    }
    public void send(){
        System.out.println("發短信");
    }
    public void show(){
        System.out.println("顯示號碼");
    }
}
//子類:新手機
public class NewPhone extends Phone{
    @Override  //輸入show,回車
    public void show() {
        super.show(); //把父類的show方法拿過來重複利用
        // 自己子類再來添加更多內容
        System.out.println("顯示姓名");
        System.out.println("顯示頭像");
    }
}
public class Demo01Phone {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.call();
        phone.send();
        phone.show();
        System.out.println("=============");

        NewPhone newPhone = new NewPhone();
        newPhone.call();
        newPhone.send();
        newPhone.show();
    }
}

結果:
在這裏插入圖片描述

繼承中構造方法的訪問特點

public class Fu {
    public Fu(){
        System.out.println("父類無參構造");
    }
    public Fu(int num){
        System.out.println("父類有參構造");
    }
}
public class Zi extends Fu {
    public Zi(){
        //下面這兩個只能調用一個
//        super();//隱含的,不用寫,自帶
        super(20);//在調用父類重載的構造方法
        System.out.println("子類構造方法");
    }
    public void method(){
//        super(); //錯誤寫法!只有子類構造方法,才能調用父類構造方法
    }
}

繼承關係中,父子類構造方法的訪問特點:

  1. 子類構造方法中有一個默認隱含的“super()”調用,所以一定是先調用父類構造,後執行子類構造
public class Demo01Constructor {
    public static void main(String[] args) {
        Zi zi = new Zi();//先出父,再出子
    }
}

結果
在這裏插入圖片描述
2. 子類構造通過super關鍵字來調用父類重載構造
3. super的父類構造調用,必須是子類構造方法的第一個語句。不能一個子類構造調用多次super構造。
4. 子類必須調用父類構造方法,不寫則贈送super(),寫了則用寫的指定的super()調用,super只能有一個,還必須是第一個。

super關鍵字的三種用法

  1. 在子類的成員方法中,訪問父類的成員變量
  2. 在子類的成員方法中,訪問父類的成員方法
  3. 在子類的構造方法中,訪問父類的構造方法

this關鍵字的三種用法

super關鍵字用來訪問父類內容,this關鍵字用來訪問本類內容

  1. 在本類的成員方法中,訪問本類的成員變量
  2. 在本類的成員方法中,訪問本類的另一個成員方法
  3. 在本類的構造方法中,訪問本類的另一個構造方法

在第三種用法種要注意:
A. this(…)調用也必須是構造方法的第一個語句
B. super和this兩種構造調用,不能同時使用

public class Zi extends Fu {
    int num = 20;
    public Zi(){
//        super();
// 1.在本類的構造方法中,訪問本類的另一個構造方法
        this(123);//本類的無參構造,調用本類的有參構造
//        this(1,2); // 寫兩個不行
    }
    public Zi(int n){
        this(1,2);
    }
    public Zi(int m,int n){
//        this(); //形成循環,不行!
        super();
    }
    public  void showNum(){
        int num = 10;
        System.out.println(num);//局部變量
        //1.在本類的成員方法中,訪問本類的成員變量
        System.out.println(this.num);//本類中的成員變量
        System.out.println(super.num); //父類中的成員變量
    }
    public void methodA(){
        System.out.println("AAA");
    }
    public void methodB(){
        this.methodA();//2.在本類的成員方法中,訪問本類的另一個成員方法
        System.out.println("BBB");
    }
}

super與this關鍵字圖解

在這裏插入圖片描述

java繼承的三個特點

在這裏插入圖片描述

抽象

圖解
在這裏插入圖片描述

抽象類和抽查方法

抽象方法:加上abstract關鍵字,然後去掉大括號,直接分號結束
抽象類:抽象方法所在的類必須是抽象類,在class之前寫上abstract即可

如何使用抽象類和抽象方法

  1. 不能直接創建抽象類對象。
  2. 必須用一個子類來繼承抽象父類
  3. 子類必須覆蓋重寫抽象父類中所有抽象方法
    覆蓋重寫(實現):去掉抽象方法的abstract關鍵字,然後不上方法體大括號
  4. 創建子類對象進行使用
public abstract class Animal {
    // 這是一個抽象方法
    public abstract void eat();
    // 這是普通的成員方法
    public void normalMethod(){
    }
}
public class Cat extends Animal {
    @Override
    public void eat(){
        System.out.println("貓喫魚");
    }
}
public class DemoMain {
    public static void main(String[] args) {
//        Animal animal = new Animal();//錯誤寫法,不能直接創建抽象類對象
        Cat cat = new Cat();
        cat.eat();
    }
}

抽象方法和抽象類的注意事項

  1. 抽象類中,可以有構造方法,是供子類創建對象時,初始化父類成員使用的
    理解:子類的構造方法中,有默認的super(),需要訪問父類構造方法
public abstract class Fu {
    public Fu(){
        System.out.println("抽象父類的構造方法執行");
    }
    public abstract void eat();
}
public class Zi extends Fu {
    public Zi(){
        //super();
        System.out.println("子類構造方法執行");
    }
    @Override
    public void eat() {
        System.out.println("喫飯飯");
    }
}
public class DemoMain {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.eat();
    }
}

結果
在這裏插入圖片描述

  1. 抽象類中,不一定有抽象方法,但抽象方法一定要在抽象類中。
    這樣沒有抽象方法的抽象類,也不能直接創建對象,在一些特殊場合下有用途。
  2. 抽象類的子類,必須覆蓋重寫所有父類的抽象方法,否則,編譯無法通過而報錯,除非該子類也是抽象類
    理解:假設不重寫所有抽象方法,則類中可能包含抽象方法,那麼創建對象後,調用抽象的方法,沒有意義。
// 最高抽象父類
public abstract class Animal {
    public abstract void sleep();
    public abstract void eat();
}
// 子類也是一個抽象類
public abstract class Dog extends Animal{

    @Override
    public void eat() {
        System.out.println("狗喫骨頭");
    }
//    public abstract void sleep();
}
// 孫子輩的
public class DogGolden extends Dog{
    @Override
    public void sleep() {
        System.out.println("呼呼呼~");
    }
}
// 孫子輩的
public class Dog2Ha extends Dog {
    @Override
    public void sleep() {
        System.out.println("嘿嘿嘿~");
    }
}
public class DemoMain {
    public static void main(String[] args) {
//        Animal animal = new Animal();//錯誤!
//        Dog dog = new Dog();//錯誤,也是抽象類
        Dog2Ha ha = new Dog2Ha();//這是普通類,可以直接new對象
        ha.sleep();
        ha.eat();
    }
}

發紅包案例

羣主發普通紅包,某羣有多名成員,羣主給成員發普通紅包,普通紅包的規則:

  1. 羣主的一筆金額,從羣主餘額中扣除,平均分成n等份,讓成員領取
  2. 成員領取紅包後,保存到成員餘額中。

題目分析
在這裏插入圖片描述

public abstract class User {
    private String name; //姓名
    private int money; //餘額

    public User() {
    }

    public User(String name, int money) {
        this.name = name;
        this.money = money;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
    //展示一下當前用戶有多少錢
    public void show(){
        System.out.println("我叫:"+name+",我有"+money+"元錢");
    }
}
//羣主
public class Manager extends User {
    public Manager() {
    }

    public Manager(String name, int money) {
        super(name, money);
    }

    public ArrayList<Integer> send(int totalMoney, int count) {
        //用一個集合存儲若干紅包的金額
        ArrayList<Integer> redList = new ArrayList<>();
        // 首先看一下羣主自己有多少錢
        int leftMoney = super.getMoney();//羣主當前餘額
        if (totalMoney > leftMoney) {
            System.out.println("餘額不足");
            return redList; //返回空集合
        }
        // 扣錢,重新設置餘額
        super.setMoney(leftMoney - totalMoney);
        // 發紅包,需要平均拆分成爲count份
        int avg = totalMoney / count;
        int mod = totalMoney % count;//餘數
        //剩下的零頭包在最後一個紅包當中
        //下面把紅包一個一個放到集合當中
        for (int i = 0; i < count-1; i++) {
            redList.add(avg);
        }
        redList.add(avg+mod);
        return redList;
    }
}
public class Member extends User {
    public Member(){
    }
    public Member(String name,int money){
        super(name, money);
    }
    public void receive(ArrayList<Integer> list){
        //從多個紅包中隨便抽取一個,給自己
        //所及獲取一個集合當中的索引編號
        int index = new Random().nextInt(list.size());
        //根據索引,從集合當中刪除
        int delta = list.remove(index);
        // 當前成員本來由多少錢
        int money = super.getMoney();
        //成員錢變多
        super.setMoney(money+delta);
    }
}
public class MainRedPacket {
    public static void main(String[] args) {
        Manager manager = new Manager("羣主",100);
        Member one = new Member("成員A",0);
        Member two = new Member("成員B",0);
        Member three = new Member("成員C",0);

        manager.show();
        one.show();
        two.show();
        three.show();
        System.out.println("============");

        // 羣主發紅包
        ArrayList<Integer> redList = manager.send(20,3);
        // 成員收紅包
        one.receive(redList);
        two.receive(redList);
        three.receive(redList);

        manager.show();
        one.show();
        two.show();
        three.show();
    }
}

太難了,要多看幾遍

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