1. 程式人生 > 實用技巧 >JavaSE進階 內部類與Lambda表示式

JavaSE進階 內部類與Lambda表示式

內部類與Lambda表示式

內部類

概述

再一個類(A)的內部,又寫了其他的類(B),此時B類就是A類的內部類;

分類

按照內部類再外部類的位置,可以分為區域性內部類和成員內部類

  • 區域性內部類:寫在了外部類的方法中;
  • 成員內部類:寫在了外部類的成員變數位置;

真正使用的都是匿名內部類;

內部類呼叫

public class Test {
    public static void main(String[] args) {
        A.C c = new B().new C();
    }
}

class A {
    class C {
    }
}

匿名內部類(重點)

匿名內部類實際上是區域性內部類的簡化形式;

我們寫了一個不帶名字的區域性內部類就是匿名內部類;(集類的編寫,物件的建立與一體)

概述

編寫沒有名字的類;

語法要求:這樣的類必須又一個父類或介面,並且寫完這個類以後,需要立刻建立物件;

語法格式

new 父類或介面(){
    重寫父類或介面方法;
};

匿名物件

建立了一個沒有名字的物件就是匿名物件

案例分析與實現

建立了一個CatInter的介面,再實現該介面列印貓吃魚

按照以往操作,需要先建立介面CatInter,再建立該介面的實現類CatImpl,重寫介面中的eat方法,列印"貓吃魚",最後在主方法中建立CatImpl物件,呼叫其中的eat方法完成列印

而學習過匿名內部類後,就可以在主方法中直接建立CatInter的內部類,重寫中的方法,在呼叫該方法就完成了

public class Test1_InnerClass {
    public static void main(String[] args) {
        /*
        匿名內部類
        父類是CatInter,但這個類本身沒有名字
         */
        new CatInter() {
            @Override
            public void eat() {
                System.out.println("貓吃魚");
            }
        }.eat();
    }
}
interface CatInter {
    void eat();
}

但思考,如果在介面中又添加了一個drink的方法,我們是不可以做}.eat.drink這樣的操作的,如果是這樣的情況,我們需要將該物件儲存到一個變數中去,再分別呼叫其中的eat方法和drink方法就可以了

public class Test2_InnerClass {
    public static void main(String[] args) {
        /*
        匿名內部類
        父類是CatInter,但這個類本身沒有名字
        這個物件被儲存到變數cat中
         */
        CatInter cat = new CatInter() {
            @Override
            public void eat() {
                System.out.println("貓吃魚");
            }
            @Override
            public void drink() {
                System.out.println("貓喝水");
            }
        };
        cat.eat();
        cat.drink();
    }
}

interface CatInter {
    void eat();
    void drink();
}

Lambda表示式

概述

lambda是java在jdk8開始新增的一種語法,這種語法允許我們在呼叫帶有介面型別的形參的方法時,使用lambda作為方法的實參使用(lambda是需要根據呼叫的場景自動進行推導的)

使用前提

方法的形參必須必須是介面型別,且介面中有且只有一個抽象方法

lambda的基本語法

(引數列表) -> {方法體;return 返回值;}
lambda必須作為方法的實參使用

省略規則

  • 引數型別可以省略,但有多個引數的情況下,不能只省略一個
  • 如果引數有且僅有一個,那麼小括號可以省略
  • 如果程式碼塊的語句只有一條,可以省略大括號、分號和return

lambda與匿名內部類的區別

所需型別不同

  • 匿名內部類:可以是介面、抽象類或者是具體類
  • Lambda:只能是介面

使用限制不同

  • 如果介面中有且僅有一個抽象方法,可以使用Lambda表示式,也可以使用匿名內部類
  • 如果介面中多於一個抽象方法,只能使用匿名內部類,而不能使用Lambda表示式

實現原理不同

  • 匿名內部類:編譯之後產生一個單獨的.class位元組碼檔案
  • Lambda:編譯之後沒有一個單獨的.class位元組碼檔案;對應的位元組碼會在執行的時候動態生成

案例分析與實現

建立Swim介面,其中有個一個swimming方法,需要傳入一個字串型別的name;建立一個goSwimming的方法,需要傳入一個介面型別的swim,呼叫裡面的swim方法,輸入名字,返回一個swimming字串,並列印xxx去游泳。

該案例我們可以使用匿名內部類來寫,現在我們既然學習了Lambda表示式,我們就可以更簡潔的來寫

我們看形參為介面型別,介面中有且僅有一個抽象方法,我們可以使用Lambda表示式

lambda的基本語法看介面中抽象方法中的需要一個String型別的name,所以小括號中填寫(String name),程式碼需要實現name去游泳並返回該字串,所以用字串拼接的方法拼接字元,然後將拼接好的字串返回return name + "去游泳";,得到lambda表示式(String name) ->{return name + "去游泳";},最後根據省略規則,引數型別可以不寫,引數只有一個,小括號可以不寫,程式碼塊中只有一條程式碼,大括號、return、分號也可以不寫,最終的lambda表示式為name ->return name + "去游泳"

public class TestSwimming {
    public static void main(String[] args) {
        goSwimming(name -> {
            return name + "去游泳";
        });
    }

    public static void goSwimming(Swim swim) {
        String swimming = swim.swimming("張三");
        System.out.println(swimming);
    }
}

interface Swim {
    String swimming(String name);
}

lambda傳遞過程

  1. 呼叫goSwimming方法,將lambda表示式作為實參傳遞給swim
  2. 呼叫swim中的swimming方法,將輸入的姓名"張三"傳遞給lambda表示式的name
  3. 執行程式碼塊中的程式碼