default關鍵字的用法
前言
在學習集合時,深入到Iterable發現了這個default關鍵字
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
理論探究
default關鍵字在java中,目前有兩個地方能用到
一是switch中的default:switch在匹配時,最后來一個default,防止因為沒有匹配到結果,使后續程序異常。
二是接口中的default:從JDK8開始,接口中可以添加默認方法了,default就是用來修飾這個方法的。
代碼實現
switch中的default
switch執行過程中,如果沒有符合條件的case,就執行default下的代碼塊,這里的default並不是必要的,也可以不寫,程序也會正常執行,只是,如果后續有業務用到這個switch的值,而代碼中又沒有匹配到相關結果,可能就會出問題。
package com.cdh.keyDefault;
/**
* @author chudonghai
* @ClassName SwitchDefaultDemo
* @Description switch中的default
*/
public class SwitchDefaultDemo {
public static void main(String[] args) {
defaultTest();
}
/*
* 判斷是否匹配:不匹配
* 輸出:ERROR!
*/
private static void defaultTest() {
String string = new String("helloworld");
switch (string) {
case "hello":
System.out.println("hello case");
break;
case "world":
System.out.println("world case");
break;
default:
System.out.println("ERROR!");
break;
}
}
}
接口中的default
重點來了,這是本篇的重頭戲,這也是JDK8加入的新特性。
接口有很多的好處,諸如多實現,低耦合,對外提供規則等;
但缺點也會在某些場景中凸顯出來,當修改接口時,需要修改全部實現該接口的類。
例如:JDK8,在Iterable中,新增了一個新方法forEach
,這里就出現一個問題。
目前,JDK8之前的版本,集合框架都沒有foreach方法,如何對已發布的接口進行修改而又不影響當前實現類的正常運行,這在生產中是一個很大的問題。對此,我們一般能想到的解決辦法是在JDK里給相關的接口添加新的方法及實現。然而,對於已經發布的版本,無法同時滿足既給接口添加新方法又不影響已有的實現,如果一味強行在每個類中進行添加,且不說風險問題,單是這個工作量就足以讓程序員們徹夜不休,如果項目龐大,這個工作量更是讓人生畏,所以,之前都是盡量避免這種改接口的問題。為此JDK8引入了默認方法default。它同時滿足了既給接口添加新方法又不影響已有的實現這個大難題。
好了扯了這一堆希望你能聽懂,不懂也沒關系,咱看看代碼:
接口中default的用法(代碼實現)
1.直接調用父接口實現
/**
* @author chudonghai
* @InterfaceName Interface1
* @Description 創建接口Interface1,並在接口中定義默認方法helloworld
*/
public interface Interface1 {
default void helloworld() {
System.out.println("this is JDK8 Interface1");
}
}
/**
* @author chudonghai
* @ClassName MyImpl1
* @Description MyImpl1:接口1的實現類,調用接口中的默認方法
*/
public class MyImpl1 implements Interface1{
public static void main(String[] args) {
MyImpl1 mi = new MyImpl1();
mi.helloworld();
}
}
此時,接口-類關系圖,如下:
結果如下:
this is JDK8 Interface1
2.繼承多個接口
/**
* @author chudonghai
* @ClassName Interface2
* @Description 創建接口Interface2,並在接口中定義默認方法helloworld
*/
public interface Interface2 {
default void helloworld() {
System.out.println("this is JDK8 Interface2");
}
}
/**
* @author chudonghai
* @ClassName MyImpl1
* @Description MyImpl1:接口1,接口2的實現類,調用接口中的默認方法
*/
public class MyImpl1 implements Interface1,Interface2{
public static void main(String[] args) {
MyImpl1 mi = new MyImpl1();
mi.helloworld();
}
}
此時發現實現類MyImpl1會報錯:Duplicate default methods named helloworld...
翻譯過來就是,名為helloworld的默認方法重復啦,,,
也就是說,現在程序不知道你到底是要運行哪個接口中的helloworld方法,怎么辦???
下面提供兩種解決辦法:
方法一:直接指定這個方法屬於哪個接口。
方法二:直接進行重寫此方法。
/**
* @author chudonghai
* @ClassName MyImpl1
* @Description MyImpl1:接口1,接口2的實現類,調用接口中的默認方法
*/
public class MyImpl1 implements Interface1,Interface2{
public static void main(String[] args) {
MyImpl1 mi = new MyImpl1();
mi.helloworld();
}
// /**
// * 方法一:直接指定這個方法屬於哪個接口
// * */
// @Override
// public void helloworld() {
// Interface1.super.helloworld();
// }
/**
* 方法二:直接重寫此方法
* */
@Override
public void helloworld() {
System.out.println("Here is MyImpl1");
}
}
此時,接口-類關系圖,如下:
方法一結果如下:
this is JDK8 Interface1
方法二結果如下:
Here is MyImpl1
3.類優先於接口
/**
* @author chudonghai
* @ClassName MyImpl2
* @Description MyImpl2繼承MyImpl1(方法helloworld已重寫)實現Interface2
*/
public class MyImpl2 extends MyImpl1 implements Interface2{
/**
* 此時,MyImpl2中調用的helloWorld到底是MyImpl1中的還是Interface2中的?
* 答案:是MyImpl1中的
* 原因:類優先於接口。從結果來看確是如此
* */
public static void main(String[] args) {
MyImpl2 mi = new MyImpl2();
mi.helloworld();
}
}
此時,接口-類關系圖,如下:
結果如下:
Here is MyImpl1
總結
default的使用場景:
- switch中的default:switch在匹配時,最后添加default,防止因為沒有匹配到結果,使后續程序異常。
- 接口中的default:從JDK8開始,接口中可以添加默認方法了,default就是用來修飾這個方法的。
①直接調用父接口實現
②繼承多個接口
③類優先於接口
=======================================================================================
善於學習,善於總結
=======================================================================================