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傳遞過程
- 呼叫goSwimming方法,將lambda表示式作為實參傳遞給swim
- 呼叫swim中的swimming方法,將輸入的姓名"張三"傳遞給lambda表示式的name
- 執行程式碼塊中的程式碼