JAVA學(xué)習(xí)筆記_面向?qū)ο?/h2>

JAVA學(xué)習(xí)筆記_面向?qū)ο?/h1>

1. 面向?qū)ο?/h2>

1.1 面向?qū)ο蟮乃枷?/h3>
  • 概述

    Java語言是一種面向?qū)ο蟮某绦蛟O(shè)計(jì)語言,而面向?qū)ο笏枷胧且环N程序設(shè)計(jì)思想,我們?cè)诿嫦驅(qū)ο笏枷氲闹敢?,使用Java語言去設(shè)計(jì)、開發(fā)計(jì)算機(jī)程序。 這里的對(duì)象泛指現(xiàn)實(shí)中一切事物,每種事物都具備自己的屬性行為。面向?qū)ο笏枷刖褪窃谟?jì)算機(jī)程序設(shè)計(jì)過程中,參照現(xiàn)實(shí)中事物,將事物的屬性特征、行為特征抽象出來,描述成計(jì)算機(jī)事件的設(shè)計(jì)思想。 它區(qū)別于面向過程思想,強(qiáng)調(diào)的是通過調(diào)用對(duì)象的行為來實(shí)現(xiàn)功能,而不是自己一步一步的去操作實(shí)現(xiàn)。

  • 面向過程:強(qiáng)調(diào)步驟。

  • 面向?qū)ο螅簭?qiáng)調(diào)對(duì)象,這里的對(duì)象就是洗衣機(jī)

  • 三大特征:

    • 繼承
    • 封裝
    • 多態(tài)

實(shí)例:輸出數(shù)組

package cn.itcast.day06.demo01;

import java.util.Arrays; // 導(dǎo)入Arrays類

public class Demo01PrintArray {

    public static void main(String[] args) {
        int[] array = { 10, 20, 30, 40, 50, 60 };

        // 要求打印格式為:[10, 20, 30, 40, 50]
        // 使用面向過程,每一個(gè)步驟細(xì)節(jié)都要親力親為。
        System.out.print("[");
        for (int i = 0; i < array.length; i++) {
            if (i == array.length - 1) { // 如果是最后一個(gè)元素
                System.out.println(array[i] + "]");
            } else { // 如果不是最后一個(gè)元素
                System.out.print(array[i] + ", ");
            }
        }
        System.out. println("==============");
        // 使用面向?qū)ο?        // 找一個(gè)JDK給我們提供好的Arrays類,
        // 其中有一個(gè)toString方法,直接就能把數(shù)組變成想要的格式的字符串
        System.out.println(Arrays.toString(array));
    }
}
  • 特點(diǎn): 特點(diǎn)面向?qū)ο笏枷胧且环N更符合我們思考習(xí)慣的思想,它可以將復(fù)雜的事情簡(jiǎn)單化,并將我們從執(zhí)行者變成了指揮者。面向?qū)ο蟮恼Z言中,包含了三大基本特征,即封裝繼承多態(tài) 。

1.2 類和對(duì)象

  • 什么是類

    • 類:是一組相關(guān)屬性和行為的集合??梢钥闯墒且活愂挛锏哪0?,使用事物的屬性特征和行為特征來描述該類事物。
    • 現(xiàn)實(shí)中,描述一類事物:
    • 屬性:就是該事物的狀態(tài)信息。
    • 行為:就是該事物能夠做什么。
  • 什么是對(duì)象:

    ? 一類事物的具體體現(xiàn)。對(duì)象是類的一個(gè)實(shí)例,必然具備該類事物的屬性和行為。

  • 類與對(duì)象的關(guān)系

    • 類是對(duì)一類事物的描述,是抽象的。
    • 對(duì)象是一類事物的實(shí)例,是具體的
    • 類是對(duì)象的模板,對(duì)象是類的實(shí)體。

1.3 類的定義

  • 屬性:事物的狀態(tài)信息。
  • 行為:事物能夠做什么。
public class ClassName {
    //成員變量
    //成員方法
}
  • 定義類:就是定義類的成員,包括成員變量和成員方法。
  • 成員變量:和以前定義變量幾乎是一樣的。只不過位置發(fā)生了改變。在類中,方法外。
  • 成員方法:把static去掉

定義一個(gè)Student類:

public class Student {

    // 成員變量
    String name; // 姓名
    int age;     // 姓名

    // 成員方法
    public void eat() {
        System.out.println("吃飯飯!");
    }

    public void sleep() {
        System.out.println("睡覺覺!");
    }

    public void study() {
        System.out.println("學(xué)習(xí)!");
    }
}

成員變量(屬性):
String name; // 姓名
int age; // 年齡
成員方法(行為):
public void eat() {} // 吃飯
public void sleep() {} // 睡覺
public void study() {} // 學(xué)習(xí)

注意事項(xiàng):

  1. 成員變量是直接定義在類當(dāng)中的,在方法外邊。
  2. 成員方法不要寫static關(guān)鍵字。

1.4 類的對(duì)象的創(chuàng)建和使用

  • 創(chuàng)建的一個(gè)Student的對(duì)象

public class Student {
    public static void main(String[] args) {
        // 1. 導(dǎo)包。
        import XXX.XXX.Student;
        // 2. 創(chuàng)建,格式:
        // 類名稱 對(duì)象名 = new 類名稱();

        Student stu = new Student();  // 根據(jù)Student類,創(chuàng)建了一個(gè)名為stu的對(duì)象

        // 3. 使用其中的成員變量,格式:
        // 對(duì)象名.成員變量名
        System.out.println(stu.name); // null
        System.out.println(stu.age);  // 0
        System.out.println("=============");

        // 改變對(duì)象當(dāng)中的成員變量數(shù)值內(nèi)容
        // 將右側(cè)的字符串,賦值交給stu對(duì)象當(dāng)中的name成員變量
        stu.name = "小明";
        stu.age = 18;
        System.out.println(stu.name); // 小明
        System.out.println(stu.age); // 18
        System.out.println("=============");

        // 4. 使用對(duì)象的成員方法,格式:
        // 對(duì)象名.成員方法名()
        stu.eat();
        stu.sleep();
        stu.study();
    }

}
  1. 導(dǎo)包:也就是指出需要使用的類,在什么位置。
    import 包名稱.類名稱;
    對(duì)于和當(dāng)前類屬于同一個(gè)包的情況,可以省略導(dǎo)包語句不寫。
  2. 創(chuàng)建,格式:
    類名稱 對(duì)象名 = new 類名稱();
    Student stu = new Student();
  3. 使用,分為兩種情況:
    使用成員變量:對(duì)象名.成員變量名
    使用成員方法:對(duì)象名.成員方法名(參數(shù))

注意事項(xiàng):
如果成員變量沒有進(jìn)行賦值,那么將會(huì)有一個(gè)默認(rèn)值,規(guī)則和數(shù)組一樣。

1.5成員變量和局部變量的區(qū)別

  • 在類中的位置不一樣

  • 成員變量:類中,方法外

  • 局部變量:方法中或者方法聲明上(形式參數(shù))

  • 作用的范圍不一樣

    • 成員變量:類中
    • 局部變量:方法中
  • **初始化值的不同 **

    • 成員變量:有默認(rèn)值
    • 局部變量:沒有默認(rèn)值。必須先定義,賦值,最后使用
  • **在內(nèi)存中的位置不同 **

    • 成員變量:堆內(nèi)存
    • 局部變量:棧內(nèi)存
  • **生命周期不同 **

    • 成員變量:隨著對(duì)象的創(chuàng)建而存在,隨著對(duì)象的消失而消失
    • 局部變量:隨著方法的調(diào)用而存在,隨著方法的調(diào)用完畢而消失

1.6 內(nèi)部類

內(nèi)部類就是一個(gè)類里面還包含另一個(gè)類

分類:

  1. 成員內(nèi)部類
  2. 局部?jī)?nèi)部類(包含匿名內(nèi)部類)

1.6.1 內(nèi)部類的格式

  • 成員內(nèi)部類

    格式:

    修飾符 class 外部類名稱 {
        修飾符 class 內(nèi)部類名稱 {
            // ...
        }
        // ...
    }
    

    注意:內(nèi)用外,隨意訪問;外用內(nèi),需要內(nèi)部類對(duì)象。

  • 局部?jī)?nèi)部類

    如果一個(gè)類是定義在一個(gè)方法內(nèi)部的,那么這就是一個(gè)局部?jī)?nèi)部類。只有當(dāng)前所屬的方法才能使用它,出了這個(gè)方法外面就不能用了。

    格式:

    修飾符 class 外部類名稱 {
        修飾符 返回值類型 外部類方法名稱(參數(shù)列表) {
            class 局部?jī)?nèi)部類名稱 {
                // ...
            }
        }
    }
    
  • 類的權(quán)限修飾符(能否使用)

    修飾符 外部類 成員內(nèi)部類 局部?jī)?nèi)部類
    public Y Y N
    protected Y Y N
    default N Y N
    private N Y N

1.6.2 內(nèi)部類使用

成員內(nèi)部類的使用
  • 兩種方法

    • 間接方式:

      在外部類的方法當(dāng)中,使用內(nèi)部類;然后main只是調(diào)用外部類的方法。

    • 直接方法:

      外部類名稱.內(nèi)部類名稱 對(duì)象名 = new 外部類名稱().new 內(nèi)部類名稱();
      
      //或 如果內(nèi)部類使用Static修飾則可使用這種方式去創(chuàng)建內(nèi)部類的對(duì)象
      外部類名稱.內(nèi)部類名稱 對(duì)象名 = new 外部類名稱.內(nèi)部類名稱();
      

    例如:

    public class Car {
        private String name;
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void methodCar() {
            System.out.println("外部Car的方法");
            // 調(diào)用內(nèi)部類的方法
            Engine engine = new Engine();
            engine.methodEngine();
        }
    
        // 定義一個(gè)內(nèi)部類
        public static class Engine {
    
            // 內(nèi)部類的方法
            public void methodEngine() {
                System.out.println("發(fā)動(dòng)機(jī)點(diǎn)火");
            }
    
        }
    }
    
局部?jī)?nèi)部類的使用

局部?jī)?nèi)部類,只有當(dāng)前所屬的方法才能使用它。

注意:

局部?jī)?nèi)部類,如果希望訪問所在方法的局部變量,那么這個(gè)局部變量必須是【有效final的】。

備注:從Java 8+開始,只要局部變量事實(shí)不變,那么final關(guān)鍵字可以省略。

原因:

  1. new出來的對(duì)象在堆內(nèi)存當(dāng)中。
  2. 局部變量是跟著方法走的,在棧內(nèi)存當(dāng)中。
  3. 方法運(yùn)行結(jié)束之后,立刻出棧,局部變量就會(huì)立刻消失。
  4. 但是new出來的對(duì)象會(huì)在堆當(dāng)中持續(xù)存在,直到垃圾回收消失。

1.6.3 * 匿名內(nèi)部類

匿名內(nèi)部類是為了省略接口的實(shí)現(xiàn)類,直接使用new來重寫接口的抽象方法。

格式:

接口名稱 對(duì)象名 = new 接口名稱() {
    // 覆蓋重寫所有抽象方法
};
public class Demo03AnonymityClass {
    public static void main(String[] args) {
        MyInterface myInterface = new MyInterface() {

            @Override
            public void method() {
                System.out.println("匿名類重寫抽象方法");
            }
        };
        myInterface.method();
    }
}

注意事項(xiàng):

  1. 匿名內(nèi)部類,在【創(chuàng)建對(duì)象】的時(shí)候,只能使用唯一一次。
  2. 匿名對(duì)象,在【調(diào)用方法】的時(shí)候,只能調(diào)用唯一一次。
  3. 匿名內(nèi)部類是省略了【實(shí)現(xiàn)類/子類名稱】,但是匿名對(duì)象是省略了【對(duì)象名稱】

2. 面向?qū)ο筇卣鳌庋b

2.1封裝的概念

面向?qū)ο缶幊陶Z言是對(duì)客觀世界的模擬,客觀世界里成員變量都是隱藏在對(duì)象內(nèi)部的,外界無法直接操作和修改。封裝可以被認(rèn)為是一個(gè)保護(hù)屏障,防止該類的代碼和數(shù)據(jù)被其他類隨意訪問。要訪問該類的數(shù)據(jù),必須通過指定的方式。適當(dāng)?shù)姆庋b可以讓代碼更容易理解與維護(hù),也加強(qiáng)了代碼的安全性。

2.2 封裝的關(guān)鍵字——private

  • private的含義:
  1. private是一個(gè)權(quán)限修飾符,代表最小權(quán)限。

  2. 可以修飾成 員變量和成員方法。

  3. 被private修飾后的成員變量和成員方法,只在本類中才能訪問。

  • private的使用格式

    private 數(shù)據(jù)類型 變量名 ;
    
  • **使用 private 修飾成員變量,代碼如下 **

    public class Student {
        private String name;
        private int age;
    }
    

    注: 使用了private本類可以直接訪問,但是在類外無法直接進(jìn)行訪問

  • 使用setXxx方法、getXxx訪問間接訪問private的成員變量

    public class Student {
        private String name;
        private int age;
        public void setName(String n) {
            name = n;
        } 
        public String getName() {
          return name;
        } 
        public void setAge(int a) {
            age = a;
        } 
        public int getAge() {
          return age;
        }
    }
    

    注:必須叫setXxx或者是getXxx命名規(guī)則。
    對(duì)于Getter來說,不能有參數(shù),返回值類型和成員變量對(duì)應(yīng);
    對(duì)于Setter來說,不能有返回值,參數(shù)類型和成員變量對(duì)應(yīng)。

  • 對(duì)于boolean類型的private成員變量的Getter方法

    public class Person {
    
        private boolean male; //性別
        public void setMale(boolean male) {
            this.male = male;
        }
        public boolean isMale() {
            return male;
        }
    }
    

2.3封裝優(yōu)化——this關(guān)鍵字

  • this 的使用:
public class Person {

    String name; // 我自己的名字

    // 參數(shù)name是對(duì)方的名字
    // 成員變量name是自己的名字
    public void sayHello(String name) {
        System.out.println(name + ",你好。我是" + this.name);
        System.out.println(this);
    }
}

當(dāng)方法的局部變量和類的成員變量重名的時(shí)候,根據(jù)“就近原則”,優(yōu)先使用局部變量。
如果需要訪問本類當(dāng)中的成員變量,需要使用格式:
this.成員變量名
通過誰調(diào)用的方法,誰就是this。

2.4 封裝優(yōu)化——構(gòu)造方法

構(gòu)造方法是專門用來創(chuàng)建對(duì)象的方法,當(dāng)我們通過關(guān)鍵字new來創(chuàng)建對(duì)象時(shí),其實(shí)就是在調(diào)用構(gòu)造方法。

  • 格式:

    public 類名稱(參數(shù)類型 參數(shù)名稱) {
        方法體
    }
    
    package cn.fate.java_learn.basic.Class;
    
    import javax.xml.namespace.QName;
    
    public class Student {
    
        private String name;
        private int age;
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public Student() {
            System.out.println("無參數(shù)構(gòu)造方法");
        }
    
        public Student(String name, int age) {
            System.out.println("帶參數(shù)的構(gòu)造方法");
            this.name = name;
            this.age = age;
        }
    
        public void show() {
            System.out.println("我叫:" + name + ",年齡:" + age);
        }
    
    }
    

    注:

    1. 構(gòu)造方法的名稱必須和所在的類名稱完全一樣,就連大小寫也要一樣。
    2. 構(gòu)造方法不要寫返回值類型、void都不寫。
    3. 構(gòu)造方法不能return一個(gè)具體的返回值。
    4. 如果沒有編寫任何構(gòu)造方法,那么編譯器將會(huì)默認(rèn)贈(zèng)送一個(gè)構(gòu)造方法,沒有參數(shù)、方法體什么事情都不做。public Student() {}
    5. 一旦編寫了至少一個(gè)構(gòu)造方法,那么編譯器將不再贈(zèng)送。
    6. 構(gòu)造方法也是可以進(jìn)行重載的。 重載:方法名稱相同,參數(shù)列表不同。

2.5 標(biāo)準(zhǔn)代碼——JavaBean

一個(gè)標(biāo)準(zhǔn)的類通常要擁有下面四個(gè)組成部分:

  1. 所有的成員變量都要使用private關(guān)鍵字修飾
  2. 為每一個(gè)成員變量編寫一對(duì)兒Getter/Setter方法
  3. 編寫一個(gè)無參數(shù)的構(gòu)造方法
  4. 編寫一個(gè)全參數(shù)的構(gòu)造方法

這樣標(biāo)準(zhǔn)的類也叫做Java Bean

  • 編寫一個(gè)標(biāo)準(zhǔn)的類
package cn.fate.java_learn.basic.Class;

public class StandardStudent {
    private String name;
    private int age;
    private boolean Male;

    public StandardStudent() {
    }

    public StandardStudent(String name, int age, boolean male) {
        this.name = name;
        this.age = age;
        Male = male;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public boolean isMale() {
        return Male;
    }

    public void setMale(boolean male) {
        Male = male;
    }
}

注 : IDEA 可以使用快捷鍵Alt+Insert快速生成Getter、Setter 及構(gòu)造方法

2.6 匿名對(duì)象

創(chuàng)建對(duì)象的標(biāo)準(zhǔn)格式:
類名稱 對(duì)象名 = new 類名稱();

匿名對(duì)象就是只有右邊的對(duì)象,沒有左邊的名字和賦值運(yùn)算符。
new 類名稱();
注意事項(xiàng):匿名對(duì)象只能使用唯一的一次,下次再用不得不再創(chuàng)建一個(gè)新對(duì)象。
使用建議:如果確定有一個(gè)對(duì)象只需要使用唯一的一次,就可以用匿名對(duì)象。

import java.util.Scanner;

public class DemoAnonymous {
    public static void main(String[] args) {

        methodParam(new Scanner(System.in));
        Scanner sc = methodReturn();
        int num = sc.nextInt();  
        System.out.println("Input num is" + num);
        methodParam(new Scannner); // 匿名對(duì)象充當(dāng)參數(shù)
    }
    public static void methodParam(Scanner sc){
        int num = sc.nextInt(); 
        System.out.printf("Input num is % d\n", num);
    }

    public static Scanner methodReturn(){
        return new Scanner(System.in); // 返回匿名對(duì)象
    }

}

3. 面向?qū)ο筇卣鳌^承

3.1 繼承的概念

繼承是java面向?qū)ο缶幊碳夹g(shù)的一塊基石,因?yàn)樗试S創(chuàng)建分等級(jí)層次的類。

繼承就是子類繼承父類的特征和行為,使得子類對(duì)象(實(shí)例)具有父類的實(shí)例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。

3.2 類的繼承格式

在 Java 中通過 extends 關(guān)鍵字可以申明一個(gè)類是從另外一個(gè)類繼承而來的,一般形式如下:

class 父類 {
}
 
class 子類 extends 父類 {
}

3.3 繼承中的成員變量的關(guān)系

父子類的繼承關(guān)系當(dāng)中,如果成員變量重名,則創(chuàng)建子類對(duì)象時(shí),訪問有兩種方式:

直接通過子類對(duì)象訪問成員變量:
等號(hào)左邊是誰,就優(yōu)先用誰,沒有則向上找。

間接通過成員方法訪問成員變量:
該方法屬于誰,就優(yōu)先用誰,沒有則向上找。

當(dāng)出現(xiàn)三種情況時(shí)的調(diào)用關(guān)系:

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

注意事項(xiàng):
無論是成員方法還是成員變量,如果沒有都是向上找父類,絕對(duì)不會(huì)向下找子類的

// 父類
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,父類的成員變量
    }
}


3.4 重寫(Override)

重寫(Override)

概念:在繼承關(guān)系當(dāng)中,方法的名稱一樣,參數(shù)列表也一樣。

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

方法的覆蓋重寫特點(diǎn):創(chuàng)建的是子類對(duì)象,則優(yōu)先用子類方法。

方法覆蓋重寫的注意事項(xiàng):

  1. 必須保證父子類之間方法的名稱相同,參數(shù)列表也相同。
    @Override:寫在方法前面,用來檢測(cè)是不是有效的正確覆蓋重寫。
    這個(gè)注解就算不寫,只要滿足要求,也是正確的方法覆蓋重寫。

  2. 子類方法的返回值必須【小于等于】父類方法的返回值范圍。
    小擴(kuò)展提示:java.lang.Object類是所有類的公共最高父類(祖宗類),java.lang.String**就是Object的子類。

  3. 子類方法的權(quán)限必須【大于等于】父類方法的權(quán)限修飾符。
    小擴(kuò)展提示:public > protected > (default) > private
    備注:(default)不是關(guān)鍵字default,而是什么都不寫,留空。

3.5 構(gòu)造方法的訪問特點(diǎn)

繼承關(guān)系中,父子類構(gòu)造方法的訪問特點(diǎn):

  1. 子類構(gòu)造方法當(dāng)中有一個(gè)默認(rèn)隱含的“super()”調(diào)用,所以一定是先調(diào)用的父類構(gòu)造,后執(zhí)行的子類構(gòu)造。
  2. 子類構(gòu)造可以通過super關(guān)鍵字來調(diào)用父類重載構(gòu)造。
  3. super的父類構(gòu)造調(diào)用,必須是子類構(gòu)造方法的第一個(gè)語句。不能一個(gè)子類構(gòu)造調(diào)用多次super構(gòu)造

總結(jié):
子類必須調(diào)用父類構(gòu)造方法,不寫則贈(zèng)送super();寫了則用寫的指定的super調(diào)用,super只能有一個(gè),還必須是第一個(gè)。

3.6 super關(guān)鍵字的三種用法:

  1. 在子類的成員方法中,訪問父類的成員變量。
  2. 在子類的成員方法中,訪問父類的成員方法。
  3. 在子類的構(gòu)造方法中,訪問父類的構(gòu)造方法。

3.7 this關(guān)鍵字的三種用法:

  1. 在本類的成員方法中,訪問本類的成員變量。
  2. 在本類的成員方法中,訪問本類的另一個(gè)成員方法。
  3. 在本類的構(gòu)造方法中,訪問本類的另一個(gè)構(gòu)造方法。

在第三種用法當(dāng)中要注意:

  • this(...)調(diào)用也必須是構(gòu)造方法的第一個(gè)語句,唯一一個(gè)。
  • superthis兩種構(gòu)造調(diào)用,不能同時(shí)使用。

總結(jié):

? super關(guān)鍵字用來訪問父類內(nèi)容,而this關(guān)鍵字用來訪問本類內(nèi)容

3.8 Java 繼承的關(guān)系

image

3.9 抽象類

抽象方法:就是加上abstract關(guān)鍵字,然后去掉大括號(hào),直接分號(hào)結(jié)束。
抽象類:抽象方法所在的類,必須是抽象類才行。在class之前寫上abstract即可。

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

  1. 不能直接創(chuàng)建new抽象類對(duì)象。
  2. 必須用一個(gè)子類來繼承抽象父類。
  3. 子類必須覆蓋重寫抽象父類當(dāng)中所有的抽象方法。
    覆蓋重寫(實(shí)現(xiàn)):子類去掉抽象方法的abstract關(guān)鍵字,然后補(bǔ)上方法體大括號(hào)。
  4. 創(chuàng)建子類對(duì)象進(jìn)行使用。
// 父類
public abstract class Animal {
    // 定義一個(gè)抽象方法
    public abstract void eat();

    // 定義一個(gè)普通的方法
    public void method() {
        System.out.printf("普通方法");
    }
}


//子類
public class Cat extends Animal {
    public void eat(){
        System.out.println("Cat eats fish");
    }
}

// Main
public class DemoAnimal {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat();
    }
}


注意事項(xiàng):

  1. 抽象類不能創(chuàng)建對(duì)象,如果創(chuàng)建,編譯無法通過而報(bào)錯(cuò)。只能創(chuàng)建其非抽象子類的對(duì)象。
    • 理解:假設(shè)創(chuàng)建了抽象類的對(duì)象,調(diào)用抽象的方法,而抽象方法沒有具體的方法體,沒有意義。
  2. 抽象類中,可以有構(gòu)造方法,是供子類創(chuàng)建對(duì)象時(shí),初始化父類成員使用的。
    • 理解:子類的構(gòu)造方法中,有默認(rèn)的super(),需要訪問父類構(gòu)造方法。
  1. 抽象類中,不一定包含抽象方法,但是有抽象方法的類必定是抽象類。

    • 理解:未包含抽象方法的抽象類,目的就是不想讓調(diào)用者創(chuàng)建該類對(duì)象,以滿足特殊類的需求。
  2. 抽象類的子類(除子類也為抽象類),必須重寫抽象父類中所有的抽象方法,否則,編譯無法通過而報(bào)錯(cuò)。

    • 理解:假設(shè)不重寫所有抽象方法,則類中可能包含抽象方法沒有意義,無法被使用。

練習(xí):紅包隨機(jī)分割。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;

public class RandomSplit {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList();
        list = divived(100, 20);
        System.out.println(list);
    }


    public static ArrayList<Integer> divived(double money, int n) {
     
        /*
         * 紅包拆分方法
         * @param money  被拆分的總金額 (單位元)
         * @param n      被拆分的紅包個(gè)數(shù)
         * @return 拆分后的每個(gè)紅包金額數(shù)組
         */
        
        // 創(chuàng)建一個(gè)長(zhǎng)度的紅包數(shù)組
        ArrayList<Integer> redList = new ArrayList<>();

        int moneyFen = (int) (money * 100);
        // 判斷紅包的總金額
        if (money > 200) {
            System.out.println("單個(gè)紅包不能超過200元");
            return redList; // 返回空的紅包集合
        }
        if (moneyFen < n || moneyFen < 1) {
            System.out.println("被拆分的總金額不能小于0.01元");
            return redList; // 返回空的紅包集合
        }
        // 創(chuàng)建一個(gè)n長(zhǎng)的數(shù)組
        Integer[] array = new Integer[n];

        //1. 給每個(gè)包分0.01元,確保每個(gè)包有錢
        Arrays.fill(array, 1);
        moneyFen -= n;   //總金額減去已分配的0.01 * n 元

        //2. 進(jìn)行隨機(jī)分配
        Random rand = new Random();

        while (moneyFen > 1) {
            int moneyCut = rand.nextInt(moneyFen);  // 隨機(jī)選擇分配的包
            int i = rand.nextInt(n);  // 隨機(jī)選擇分配的包
            array[i] += moneyCut; // 分配給每一個(gè)包并且轉(zhuǎn)換為元
            moneyFen -= (int) moneyCut;
        }
        //把最后的包放到最后一個(gè)包里面
        array[n - 1] += moneyFen ;
        // 把分好的包放到redList里面
        Collections.addAll(redList, array);

        return redList;
    }
}

4. 面向?qū)ο筇卣鳌鄳B(tài)

4.1 多態(tài)的概念

多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力。

多態(tài)存在的三個(gè)必要條件:

  • 繼承
  • 重寫
  • 父類引用指向子類對(duì)象

4.2 多態(tài)的個(gè)格式

格式:

父類名稱 對(duì)象名 = new 子類名稱();
// 或者:
接口名稱 對(duì)象名 = new 實(shí)現(xiàn)類名稱();

4.3 多態(tài)中的成員變量和成員方法

  • 訪問成員變量的兩種方式:

    1. 直接通過對(duì)象名稱訪問成員變量:看等號(hào)左邊是誰,優(yōu)先用誰,沒有則向上找。
    2. 間接通過成員方法訪問成員變量:看該方法屬于誰,優(yōu)先用誰,沒有則向上找。
  • 成員方法的訪問規(guī)則是:
    new的是誰,就優(yōu)先用誰,沒有則向上找。

成員變量:編譯看左邊,運(yùn)行還看左邊。
成員方法:編譯看左邊,運(yùn)行看右邊。
口訣: 編譯看左邊,運(yùn)行看右邊。

4.4 對(duì)象的轉(zhuǎn)型

  • 向上轉(zhuǎn)型:多態(tài)本身是子類類型向父類類型向上轉(zhuǎn)換的過程,這個(gè)過程是默認(rèn)的。當(dāng)父類引用指向一個(gè)子類對(duì)象時(shí),便是向上轉(zhuǎn)型 。

    向上轉(zhuǎn)型是安全的,等于從小范圍轉(zhuǎn)向大的范圍。

    格式:

    父類類型 變量名 = new 子類類型();
    // 比如
    Animal a = new Cat();
    
  • 向下轉(zhuǎn)型:父類類型向子類類型向下轉(zhuǎn)換的過程,這個(gè)過程是強(qiáng)制的。

    注: 向下轉(zhuǎn)型的對(duì)象,之前的必須是通過向上轉(zhuǎn)型過來的,才能向下轉(zhuǎn)回原來的對(duì)象。

    格式:

    子類類型 變量名 = (子類類型) 父類變量名;
    // 比如:
    Cat c =(Cat) a;
    

    向下轉(zhuǎn)型的異常:

    ? 如果錯(cuò)誤的轉(zhuǎn)換為其他對(duì)象,編譯時(shí)會(huì)出現(xiàn) ClassCastException的報(bào)錯(cuò)。為了確定向下轉(zhuǎn)型的正確性,我們可以使用關(guān)鍵字 instanceof ,進(jìn)行校驗(yàn)。

    校驗(yàn)格式:

    變量名 instanceof 數(shù)據(jù)類型
    如果變量屬于該數(shù)據(jù)類型,返回true。
    如果變量不屬于該數(shù)據(jù)類型,返回false。
    

    實(shí)例:

    public class Test {
        public static void main(String[] args) {
            // 向上轉(zhuǎn)型
            Animal a = new Cat();
            a.eat(); // 調(diào)用的是 Cat 的 eat
            // 向下轉(zhuǎn)型
            if (a instanceof Cat) {
                Cat c = (Cat) a;
                c.catchMouse(); // 調(diào)用的是 Cat 的 catchMouse
            } else if (a instanceof Dog) {
                Dog d = (Dog) a;
                d.watchHouse(); // 調(diào)用的是 Dog 的 watchHouse
            }
        }
    }
    

5. Java中的接口

接口就是多個(gè)類的公共規(guī)范。

接口(Interface),在JAVA編程語言中是一個(gè)抽象類型,是抽象方法的集合,接口通常以interface來聲明。一個(gè)類通過繼承接口的方式,從而來繼承接口的抽象方法。

接口是一種引用數(shù)據(jù)類型,最重要的內(nèi)容就是其中的:抽象方法。

接口并不是類,編寫接口的方式和類很相似,但是它們屬于不同的概念。類描述對(duì)象的屬性和方法。接口則包含類要實(shí)現(xiàn)的方法。

除非實(shí)現(xiàn)接口的類是抽象類,否則該類要定義接口中的所有方法。

接口無法被實(shí)例化,但是可以被實(shí)現(xiàn)。一個(gè)實(shí)現(xiàn)接口的類,必須實(shí)現(xiàn)接口內(nèi)所描述的所有方法,否則就必須聲明為抽象類。另外,在 Java 中,接口類型可用來聲明一個(gè)變量,他們可以成為一個(gè)空指針,或是被綁定在一個(gè)以此接口實(shí)現(xiàn)的對(duì)象。

如果是Java 7,那么接口中可以包含的內(nèi)容有:

  1. 常量
  2. 抽象方法

如果是Java 8,還可以額外包含有:

  1. 默認(rèn)方法
  2. 靜態(tài)方法

如果是Java 9,還可以額外包含有:

  1. 私有方法

4.1 定義接口的格式

public interface 接口名稱 [extends 其他的接口名] {
       // 聲明變量
       // 抽象方法
}

接口有以下特性:

  • 接口是隱式抽象的,當(dāng)聲明一個(gè)接口的時(shí)候,不必使用abstract關(guān)鍵字。
  • 接口中每一個(gè)方法也是隱式抽象的,聲明時(shí)同樣不需要abstract關(guān)鍵字。
  • 接口中的方法都是公有的。

4.2 接口的使用步驟

  1. 接口不能直接使用,必須有一個(gè)“實(shí)現(xiàn)類”來“實(shí)現(xiàn)”該接口。
    格式:
public class 實(shí)現(xiàn)類名稱 implements 接口名稱 {
    // ...
}
  1. 接口的實(shí)現(xiàn)類必須覆蓋重寫(override)接口中所有的抽象方法。

  2. 創(chuàng)建實(shí)現(xiàn)類的對(duì)象,進(jìn)行使用。

4.3 接口中抽象(abstract)方法

在任何版本的Java中,接口都能定義抽象方法。
格式:

public abstract 返回值類型 方法名稱(參數(shù)列表){
     //方法體
};

注意事項(xiàng):

  1. 接口當(dāng)中的抽象方法,修飾符必須是兩個(gè)固定的關(guān)鍵字:public abstract
  2. public abstract關(guān)鍵字修飾符可以選擇性地省略。
  3. 方法的三要素,可以隨意定義。
  4. 實(shí)現(xiàn)類并沒有覆蓋重寫接口中所有的抽象方法,那么這個(gè)實(shí)現(xiàn)類自己就必須是抽象類。
public interface MyInterfaceAbstract {

    // 這是一個(gè)抽象方法
    public abstract void methodAbs1();

    // 這也是抽象方法
    abstract void methodAbs2();

    // 這也是抽象方法
    public void methodAbs3();

    // 這也是抽象方法
    void methodAbs4();
}

4.4 接口中的默認(rèn)(default)方法

從Java 7開始,接口當(dāng)中允許定義Default方法。

接口中使用的默認(rèn)方法,可以解決接口升級(jí)的問題。默認(rèn)方法,實(shí)現(xiàn)類可以不重寫。

格式:

public default 返回值類型 方法名稱(參數(shù)列表) {
    方法體
}

注:

  1. 關(guān)鍵字public 修飾符可以選擇性地省略。
  2. 接口的默認(rèn)方法,可以通過接口實(shí)現(xiàn)類對(duì)象,直接調(diào)用。
  3. 接口的默認(rèn)方法,也可以被接口實(shí)現(xiàn)類進(jìn)行覆蓋重寫。
    public interface MyInterfaceDefault {
        // 抽象方法
        public abstract void methodAbstract();

        // 默認(rèn)方法
        public default void methodDefault() {
            System.out.println("默認(rèn)方法");
        }
}

4.5 接口中的私有(private)方法

從Java 9開始,接口當(dāng)中允許定義私有方法。

  1. 普通私有方法,解決多個(gè)默認(rèn)方法之間重復(fù)代碼問題

格式:

private 返回值類型 方法名稱(參數(shù)列表) {
 方法體
}
  1. 靜態(tài)私有方法,解決多個(gè)靜態(tài)方法之間重復(fù)代碼問題
    格式:
private static 返回值類型 方法名稱(參數(shù)列表) {
 方法體
}
public interface MyInterfacePrivate {
    public default void methodDefault1() {
        System.out.println("默認(rèn)方法1");
        methodDefaultCommon();
    }

    public default void methodDefault2() {
        System.out.println("默認(rèn)方法2");
        methodDefaultCommon();
    }

    public static void methodStatic1() {
        System.out.println("靜態(tài)方法1");
        methodStaticCommon();
    }

   public static void methodStatic2() {
        System.out.println("靜態(tài)方法2");
        methodStaticCommon();
    }

    private static void methodStaticCommon() {
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }

    private void methodDefaultCommon() {
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }
}

4.6 接口中的靜態(tài)(static)方法

從Java 8開始,接口當(dāng)中允許定義靜態(tài)方法。
格式:

public static 返回值類型 方法名稱(參數(shù)列表) {
    方法體
}

注 :

  1. 關(guān)鍵字public 修飾符可以選擇性地省略。
  2. 靜態(tài)方法的調(diào)用通過接口名稱直接調(diào)用,而不是使用實(shí)現(xiàn)類的對(duì)象進(jìn)行調(diào)用,因?yàn)殪o態(tài)和對(duì)象沒關(guān)系。
public interface MyInterfaceStatic {
    public static void methodStatic() {
        System.out.println("這是接口的靜態(tài)方法!");
    }
}

4.7 接口中的常量的定義和使用

接口當(dāng)中也可以定義“成員變量”,但是必須使用public static final三個(gè)關(guān)鍵字進(jìn)行修飾。
從效果上看,這其實(shí)就是接口的【常量】。
格式:

public static final 數(shù)據(jù)類型 常量名稱 = 數(shù)據(jù)值;

// public static final 都可以省略

數(shù)據(jù)類型 常量名稱 = 數(shù)據(jù)值;

備注:
一旦使用final關(guān)鍵字進(jìn)行修飾,說明不可改變。

備注:
一旦使用final關(guān)鍵字進(jìn)行修飾,說明不可改變。

注意事項(xiàng):

  1. 接口當(dāng)中的常量,可以省略public static final,注意:其實(shí)都可以省略。
  2. 接口當(dāng)中的常量,必須進(jìn)行賦值;不能不賦值。
  3. 接口中常量的名稱,使用完全大寫的字母,用下劃線進(jìn)行分隔。(推薦命名規(guī)則)
  4. 調(diào)用常量時(shí)使用接口名稱去調(diào)用。

4.8 接口中方法的總結(jié)

  1. 成員變量其實(shí)是常量,格式:
[public] [static] [final] 數(shù)據(jù)類型 常量名稱 = 數(shù)據(jù)值;

注意:
常量必須進(jìn)行賦值,而且一旦賦值不能改變。
常量名稱完全大寫,用下劃線進(jìn)行分隔。

注意:
常量必須進(jìn)行賦值,而且一旦賦值不能改變。
常量名稱完全大寫,用下劃線進(jìn)行分隔。

  1. 接口中最重要的就是抽象方法,格式:
[public] [abstract] 返回值類型 方法名稱(參數(shù)列表);

注意:實(shí)現(xiàn)類必須覆蓋重寫接口所有的抽象方法,除非實(shí)現(xiàn)類是抽象類。

注意:實(shí)現(xiàn)類必須覆蓋重寫接口所有的抽象方法,除非實(shí)現(xiàn)類是抽象類。

  1. 從Java 8開始,接口里允許定義默認(rèn)方法,格式:
[public] default 返回值類型 方法名稱(參數(shù)列表) { 方法體 }

注意:默認(rèn)方法也可以被覆蓋重寫

注意:默認(rèn)方法也可以被覆蓋重寫

  1. 從Java 8開始,接口里允許定義靜態(tài)方法,格式:
[public] static 返回值類型 方法名稱(參數(shù)列表) { 方法體 }

注意:應(yīng)該通過接口名稱進(jìn)行調(diào)用,不能通過實(shí)現(xiàn)類對(duì)象調(diào)用接口靜態(tài)方法

注意:應(yīng)該通過接口名稱進(jìn)行調(diào)用,不能通過實(shí)現(xiàn)類對(duì)象調(diào)用接口靜態(tài)方法

  1. 從Java 9開始,接口里允許定義私有很乏,格式:
    普通私有方法:
private 返回值類型 方法名稱(參數(shù)列表) { 方法體 }

靜態(tài)私有方法:

private static 返回值類型 方法名稱(參數(shù)列表) { 方法體 }

注意:private的方法只有接口自己才能調(diào)用,不能被實(shí)現(xiàn)類或別人使用。

4.9 類的繼承和實(shí)現(xiàn)接口的問題

類的繼承關(guān)系是單繼承的,但類可同時(shí)實(shí)現(xiàn)多個(gè)接口。

使用接口時(shí)的注意事項(xiàng):

  1. 接口是沒有者構(gòu)造方法的。
  2. 一個(gè)類的直接父類是唯一的,但是一個(gè)類可以同時(shí)實(shí)現(xiàn)多個(gè)接口。
  3. 實(shí)現(xiàn)類所實(shí)現(xiàn)的多個(gè)接口當(dāng)中,存在重復(fù)的抽象方法,只需要覆蓋重寫一次即可。
  4. 實(shí)現(xiàn)類沒有覆蓋重寫所有接口當(dāng)中的所有抽象方法,實(shí)現(xiàn)類就必須是一個(gè)抽象類。
  5. 實(shí)現(xiàn)類實(shí)現(xiàn)的多個(gè)接口當(dāng)中,存在重復(fù)的默認(rèn)方法,實(shí)現(xiàn)類一定要對(duì)沖突的默認(rèn)方法進(jìn)行覆蓋重寫。
  6. 一個(gè)類如果直接父類當(dāng)中的方法和接口當(dāng)中的默認(rèn)方法產(chǎn)生了沖突,優(yōu)先用父類當(dāng)中的方法。

4.10 接口之間的多繼承

在Java中,類的多繼承是不合法,但接口允許多繼承。

在接口的多繼承中extends關(guān)鍵字只需要使用一次,在其后跟著繼承接口。

格式:

public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
    // 覆蓋重寫所有抽象方法
}

注意事項(xiàng):

  1. 多個(gè)父接口當(dāng)中的抽象方法如果重復(fù),由于實(shí)現(xiàn)類中必重寫抽象方法,說以沒影響。
  2. 多個(gè)父接口當(dāng)中的默認(rèn)方法如果重復(fù),那么子接口必須進(jìn)行默認(rèn)方法的覆蓋重寫。

綜合案例

  • 問題:

    筆記本電腦(laptop)通常具備使用USB設(shè)備的功能。在生產(chǎn)時(shí),筆記本都預(yù)留了可以插入U(xiǎn)SB設(shè)備的USB接口,但具體是什么USB設(shè)備,筆記本廠商并不關(guān)心,只要符合USB規(guī)格的設(shè)備都可以。定義USB接口,具備最基本的開啟功能和關(guān)閉功能。鼠標(biāo)和鍵盤要想能在電腦上使用,那么鼠標(biāo)和鍵盤也必須遵守USB規(guī)范,實(shí)現(xiàn)USB接口,否則鼠標(biāo)和鍵盤的生產(chǎn)出來也無法使用。

  • 分析:

    • USB接口,包含開啟功能、關(guān)閉功能
    • 筆記本類,包含運(yùn)行功能、關(guān)機(jī)功能、使用USB設(shè)備功能
    • 鼠標(biāo)類,要實(shí)現(xiàn)USB接口,并具備點(diǎn)擊的方法
    • 鍵盤類,要實(shí)現(xiàn)USB接口,具備敲擊的方法
    // Usb接口
    
    public interface Usb {
    
        public abstract void on();
    
        public abstract void off();
    }
    
    
    // Mouse 鼠標(biāo)類
    public class Mouse implements Usb {
        @Override
        public void on() {
            System.out.println("開啟鼠標(biāo)");
        }
    
        @Override
        public void off() {
            System.out.println("關(guān)閉鼠標(biāo)");
        }
    
        public void click() {
            System.out.println("鼠標(biāo)點(diǎn)擊");
        }
    }
    
    
    
    // 鍵盤類
    public class Keboard implements Usb {
    
        @Override
        public void on() {
            System.out.println("開啟鍵盤");
        }
    
        @Override
        public void off() {
            System.out.println("關(guān)閉鍵盤");
        }
    
        public void inputs() {
            System.out.println("鍵盤輸出");
        }
    }
    
    // 電腦類
    public class Computer {
        public void powerOn() {
            System.out.println("開啟電腦");
        }
    
        public void powerOff() {
            System.out.println("關(guān)閉電腦");
        }
    
        public void useDevice(Usb usb) {
            // 開啟Usb設(shè)備
            usb.on();
    
            // 使用Usb設(shè)備
            if (usb instanceof Keboard) {
                // 向下轉(zhuǎn)換為鍵盤
                Keboard keboard = (Keboard) usb;
                keboard.inputs();
            } else if (usb instanceof Mouse) {
                // 向下轉(zhuǎn)換為鼠標(biāo)
                Mouse mouse = (Mouse) usb;
                mouse.click();
            }
    
            // 關(guān)閉usb設(shè)備
            usb.off();
        }
    }
    
    // 測(cè)試
    
    public class DemoMain {
        public static void main(String[] args) {
            Computer computer = new Computer();
            // 開啟電腦
            computer.powerOn();
    
            // 向上轉(zhuǎn)換出一個(gè)use
            Usb usb = new Mouse();
            computer.useDevice(usb);
    
    
            // 直接傳入一個(gè)usb設(shè)備
            Keboard keboard = new Keboard();
            computer.useDevice(keboard);  // 掉用過程: 參數(shù)傳過去先向上轉(zhuǎn)換, 再向下轉(zhuǎn)換。
            // 關(guān)閉電腦
            computer.powerOff();
        }
    }  
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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