1. 程式人生 > 其它 >java介面的使用(二)

java介面的使用(二)

技術標籤:java

在繼承體系中,一個類只能繼承一個父類。而對於介面而言,一個類是可以實現多個介面的,這叫做介面的多實現。並且,一個類能繼承一個父類,同時實現多個介面。
注意事項:
使用介面的時候,需要注意:

  1. 介面是沒有靜態程式碼塊或者構造方法的。
  2. 一個類的直接父類是唯一的,但是一個類可以同時實現多個介面。
    格式:
    public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
    // 覆蓋重寫所有抽象方法
    }
  3. 如果實現類所實現的多個介面當中,存在重複的抽象方法,那麼只需要覆蓋重寫一次即可。
  4. 如果實現類沒有覆蓋重寫所有介面當中的所有抽象方法,那麼實現類就必須是一個抽象類。
  5. 如果實現類實現的多個介面當中,存在重複的預設方法,那麼實現類一定要對衝突的預設方法進行覆蓋重寫。
  6. 一個類如果直接父類當中的方法,和介面當中的預設方法產生了衝突,優先用父類當中的方法。

實戰:
介面A

package cn.itcast.day10.demo02;

public interface MyInterfaceA {

    // 錯誤寫法!介面中不能有靜態程式碼塊
//    static{
//
//    }

    // 錯誤寫法!介面中不能有構造方法
//    public MyInterfaceA(){}


    public abstract void methodA();

    public
abstract void methodAbs(); public default void methodDefault(){ System.out.println("預設方法AAA"); } }

介面B

package cn.itcast.day10.demo02;

public interface MyInterfaceB {

    // 錯誤寫法!介面不能有靜態程式碼塊
//    static {
//
//    }

    // 錯誤寫法!介面不能有構造方法
//    public MyInterfaceA(){
//
//    }

    public
abstract void methodB(); public abstract void methodAbs(); public default void methodDefault(){ System.out.println("預設方法BBB"); } }

實現類實現介面A,B; 沒有覆蓋重寫介面A,B中所有的抽象方法,因此該類必須是抽象類

package cn.itcast.day10.demo02;

public abstract class MyInterfaceAbstract implements MyInterfaceA, MyInterfaceB{
    @Override
    public void methodA() {

    }

//    @Override
//    public void methodB() {
//
//    }

    @Override
    public void methodAbs() {

    }

    @Override
    public void methodDefault(){

    }
}

實現類覆蓋重寫了A,B介面中的所有抽象方法,並對衝突的預設方法進行了覆蓋重寫

package cn.itcast.day10.demo02;

public class MyInterfaceImpl /*extends Object*/ implements MyInterfaceA, MyInterfaceB{


    @Override
    public void methodA() {
        System.out.println("覆蓋重寫了A方法");

    }

    @Override
    public void methodB() {
        System.out.println("覆蓋重寫了B方法");
    }

    @Override
    public void methodAbs() {
        System.out.println("覆蓋重寫了AB介面中都有的抽象方法");

    }

    @Override
    public void methodDefault(){
        System.out.println("對多個介面當中衝突的預設方法進行覆蓋重寫");
    }
}

一個類如果直接父類當中的方法,和介面當中的預設方法產生了衝突,優先用父類當中的方法。
父類:

package cn.itcast.day10.demo02;

public class Fu {

    public void method(){
        System.out.println("父類方法");
    }
}

介面:

package cn.itcast.day10.demo02;

public interface MyInterface {

    public default void method(){
        System.out.println("介面的預設方法");
    }
}

實現類,繼承父類方法並且實現介面

package cn.itcast.day10.demo02;

public class Demo01Interface {

    public static void main(String[] args) {

        Zi zi = new Zi();

        zi.method();
    }
}

結果如下所示:
在這裡插入圖片描述

  1. 類與類之間是單繼承的。直接父類只有一個。
  2. 類與介面之間是多實現的。一個類可以實現多個介面。
    3. 介面與介面之間是多繼承的。

注意事項:

  1. 多個父介面當中的抽象方法如果重複,沒關係。
    2. 多個父介面當中的預設方法如果重複,那麼子介面必須進行預設方法的覆蓋重寫,【而且帶著default關鍵字】。

父類介面A

package cn.itcast.day10.demo03;

public interface MyInterfaceA {

    public abstract void methodA();

    public abstract void methodCommon();

    public default void methodDefault(){
        System.out.println("AAA");
    }
}

父類介面B

package cn.itcast.day10.demo03;

public interface MyInterfaceB {

    public abstract void methodB();
    public abstract void methodCommon();

    public default void methodDefault(){
        System.out.println("BBB");
    }
}

子介面繼承介面A,B

package cn.itcast.day10.demo03;

public interface MyInterface extends MyInterfaceA, MyInterfaceB{
    public abstract void method();

    @Override
    public default void methodDefault(){

    }

}

介面中的多型性

程式碼當中體現多型性,其實就是一句話:父類引用指向子類物件。
格式:
父類名稱 物件名 = new 子類名稱();
或者:
介面名稱 物件名 = new 實現類名稱();

下面介紹類中的多型性:
父類:

package cn.itcast.day10.demo04;

public class Fu {

    public void method(){
        System.out.println("父類方法");
    }

    public void methodFu(){
        System.out.println("父類特有方法");
    }
}

子類方法

package cn.itcast.day10.demo04;

public class Zi extends Fu{

    @Override
    public void method(){
        System.out.println("子類方法");
    }
}

main方法

package cn.itcast.day10.demo04;

public class Demo01Multi {


    public static void main(String[] args) {

        // 使用多型的寫法
        // 左側父類的引用,指向了右側子類的物件
        Fu obj = new Zi();

        obj.method();
        obj.methodFu();
    }
}

執行結果:
在這裡插入圖片描述
多型中成員變數的訪問規則:

訪問成員變數的兩種方式:

  1. 直接通過物件名稱訪問成員變數:看等號左邊是誰,優先用誰,沒有則向上找。
  2. 間接通過成員方法訪問成員變數:看該方法屬於誰,優先用誰,沒有則向上找。

在多型的程式碼當中,成員方法的訪問規則是:
看new的是誰,就優先用誰,沒有則向上找。

口訣:編譯看左邊,執行看右邊。

對比一下:
成員變數:編譯看左邊,執行還看左邊。
成員方法:編譯看左邊,執行看右邊。

父類

package cn.itcast.day10.demo05;

public class Fu {

    int num = 10;

    public void showNum(){

        System.out.println(num);

    }

    public void method(){
        System.out.println("父類方法");
    }

    public void methodFu(){
        System.out.println("父類特有方法");
    }
}

子類

package cn.itcast.day10.demo05;

public class Zi extends Fu{

    int num = 20;

    int age = 16;

    @Override
    public void showNum(){
        System.out.println(num);
    }

    @Override
    public void method(){
        System.out.println("子類方法");
    }


    public void methodZi(){
        System.out.println("子類特有方法");
    }


}

main1方法,訪問成員變數

package cn.itcast.day10.demo05;

public class Demo01MultiField {

    public static void main(String[] args) {


        // 使用多型的寫法,父類引用指向子類物件
        Fu obj = new Zi();

        System.out.println(obj.num);

        System.out.println("=======");

        // 子類沒有覆蓋重寫,就是父:10
        // 子類如果覆蓋重寫,就是子:20
        obj.showNum();


    }
}

結果如下所示:
在這裡插入圖片描述
main方法,訪問成員方法

package cn.itcast.day10.demo05;

public class Demo02MultiMethod {

    public static void main(String[] args) {

        Fu obj = new Zi();// 多型

        obj.method();// 父子都有,優先用子

        obj.methodFu();//子類沒有,父類有,向上查詢父類

        // 編譯看左邊,執行看右邊,左邊是Fu,Fu當中沒有methodZi方法,所以編譯報錯。
//        obj.methodZi();
    }
}

結果如下所示:
在這裡插入圖片描述

物件的向上、向下轉型

實戰一
父類

package cn.itcast.day10.demo06;

public abstract class Animal {

    public abstract void eat();
}

子類1

package cn.itcast.day10.demo06;

public class Cat extends Animal{


    @Override
    public void eat() {
        System.out.println("貓吃魚");
    }

    // 子類特有方法
    public void catchMouse(){
        System.out.println("貓抓老鼠");
    }
}

子類2

package cn.itcast.day10.demo06;

public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃SHIT");
    }

    public void watchHouse(){
        System.out.println("狗看家");
    }


}

mian函式1

package cn.itcast.day10.demo06;

public class Demo01Main {

    public static void main(String[] args) {

        // 物件的向上的轉型,就是:父類引用指向子類物件
        Animal animal = new Cat();
        animal.eat();// 貓吃魚

        // 向下轉型,進行"還原"動作
        Cat cat = (Cat) animal;
        cat.catchMouse();// 貓抓老鼠

        // 下面是錯誤的向下轉型
        // 本來new的時候是一隻貓,非要當作狗
        // 錯誤寫法!編譯不會報錯,但是執行會出現異常
        Dog dog = (Dog) animal;





    }
}

執行結果
在這裡插入圖片描述
mian方法二
向下轉型的判斷
如何才能知道一個父類引用的物件,本來是什麼子類?
格式:
物件 instanceof 類名稱
這將會得到一個boolean值結果,也就是判斷前面的物件能不能當做後面型別的例項。

package cn.itcast.day10.demo06;

public class Demo02Instanceof {

    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.eat();// 狗吃SHIT

        // 如果希望呼叫子類特有的方法,需要向下轉型
        // 判斷一下父類引用animal本來是不是Dog

        if (animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.watchHouse();
        }

        // 判斷一下animal本來是不是Cat

        if (animal instanceof Cat){
            Cat cat = (Cat) animal;
            cat.catchMouse();


        }

        giveMeAPet(new Dog());


    }

    public static void giveMeAPet(Animal animal){

        if (animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.watchHouse();
        }

        if (animal instanceof Cat){
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }

    }


}

在這裡插入圖片描述
實戰二(介面中的多型)
computer類

package cn.itcast.day10.demo07;

public class Computer {

    public void powerOn() {
        System.out.println("膝上型電腦開機");
    }

    public void powerOff() {
        System.out.println("膝上型電腦關機");
    }

    // 使用USB裝置的方法,使用介面作為方法的引數
    public void useDevice(USB usb) {
        usb.open(); // 開啟裝置
        if (usb instanceof Mouse) { // 一定要先判斷
            Mouse mouse = (Mouse) usb; // 向下轉型
            mouse.click();
        } else if (usb instanceof Keyboard) { // 先判斷
            Keyboard keyboard = (Keyboard) usb; // 向下轉型
            keyboard.type();
        }
        usb.close(); // 關閉裝置
    }

}

USB介面

package cn.itcast.day10.demo07;

public interface USB {

    public abstract void open(); // 開啟裝置

    public abstract void close(); // 關閉裝置

}

鍵盤類實現USB介面

package cn.itcast.day10.demo07;

// 鍵盤就是一個USB裝置
public class Keyboard implements USB {
    @Override
    public void open() {
        System.out.println("開啟鍵盤");
    }

    @Override
    public void close() {
        System.out.println("關閉鍵盤");
    }

    public void type() {
        System.out.println("鍵盤輸入");
    }
}

滑鼠類實現USB介面

package cn.itcast.day10.demo07;

// 滑鼠就是一個USB裝置
public class Mouse implements USB {
    @Override
    public void open() {
        System.out.println("開啟滑鼠");
    }

    @Override
    public void close() {
        System.out.println("關閉滑鼠");
    }

    public void click() {
        System.out.println("滑鼠點選");
    }
}

main方法:

package cn.itcast.day10.demo07;

public class DemoMain {

    public static void main(String[] args) {
        // 首先建立一個膝上型電腦
        Computer computer = new Computer();
        computer.powerOn();

        // 準備一個滑鼠,供電腦使用
//        Mouse mouse = new Mouse();
        // 首先進行向上轉型
        USB usbMouse = new Mouse(); // 多型寫法
        // 引數是USB型別,我正好傳遞進去的就是USB滑鼠
        computer.useDevice(usbMouse);

        // 建立一個USB鍵盤
        Keyboard keyboard = new Keyboard(); // 沒有使用多型寫法
        // 方法引數是USB型別,傳遞進去的是實現類物件
        computer.useDevice(keyboard); // 正確寫法!也發生了向上轉型
        // 使用子類物件,匿名物件,也可以
//        computer.useDevice(new Keyboard()); // 也是正確寫法

        computer.powerOff();
        System.out.println("==================");

        method(10.0); // 正確寫法,double --> double
        method(20); // 正確寫法,int --> double
        int a = 30;
        method(a); // 正確寫法,int --> double
    }

    public static void method(double num) {
        System.out.println(num);
    }

}