default 关键字(虚拟扩展方法)
前言
也可称为Virtual extension methods——虚拟扩展方法。是指,在接口内部包含了一些默认的方法实现(也就是接口中可以包含方法体,这打破了Java之前版本对接口的语法限制),从而使得接口在进行扩展的时候,不会破坏与接口相关的实现类代码。
一、作用(为什么要有这个方法)
default关键字,成为虚拟扩展方法或者守护方法。
他的主要是作用是什么呢?你可以想想一个场景!
JDK7中有一个接口(我们暂且叫他InterfaceOne),然后有一系列的类实现了这个接口(这里叫这些类为ClassB)。他的子类又继承了ClassB(子类叫ClassC)。有一天,JDK的开发者们,想在InterfaceOne中加上一个抽象方法。但是,遇到了一个难题,这个难题是虽然在这个InterfaceOne接口中加上了这个方法,但是他的实现类(ClassB)、甚至他的实现类的子类(ClassC)都要实现这个方法。由此想象,这个工程量是不是巨大的。
为了应对上述这个场景,在JDK8的时候引入了default扩展方法。以此达到可以做到JDK版本升级的时候,向某个接口添加抽象方法,其实现类不会受到任何影响,以达到在进行接口扩展时,不会破坏与接口相关的实现类的目的,做到向下兼容(向前兼容)。
二、具体代码示例
1.接口(小猫出生)
我们对于刚出生的小猫进行抽象,它会cry和对世界说helloWorld。
package defaultVitual;
public interface MyCat{
public abstract void cry();
}
有一天,我们真的得到了一直小猫,这个小猫的叫声(cry)是“喵喵、喵喵”,对世界说helloWorld。这个它刚出生的时候(JDK7版本)
package defaultVitual;
/**
* MyCat
*/
public class MyCatImplement implements MyCat{
public static void main(String[] args) {
MyCatImplement mycat = new MyCatImplement();
//直接调用helloWorld()方法
mycat.cry();
}
@Override
public void cry() {
System.out.println("我是小猫:我会喵喵、喵喵");
}
}
执行结果:
2、向前兼容 (小猫长大啦)
长大后的小猫的抽象。它不仅会cry和对世界说helloWorld,还学会抓老鼠啦。我们要对这个小猫的抽象方法进行修改啦。
可以想象一下,如果我们直接在接口中再定义一个抽象方法。是不是我们的小猫实现类是不是也要跟着重写呢,如果是一个小猫还好说,如果出现很多个小猫接口的实现类呢,RedCat、BigCat,是否都要重写呢,是不是很麻烦呢。所以这个时候,我们使用default关键字。
package defaultVitual;
public interface MyCat{
public abstract void cry();
default void catchMouse() {
System.out.println("我是小猫,我不仅会喵喵,我还会抓老鼠啦");
}
}
长大后的小猫:
package defaultVitual;
/**
* MyCat
*/
public class MyCatImplement implements MyCat{
public static void main(String[] args) {
MyCatImplement mycat = new MyCatImplement();
//直接调用helloWorld()方法
mycat.cry();
mycat.catchMouse();
}
@Override
public void cry() {
System.out.println("我是小猫:我会喵喵、喵喵");
}
}
运行结果:
通过这个样子,我们只需要修改小猫的接口,加上虚拟扩展方法,不再需要对小猫的实现类进行扩展。是不是省去了很大的工作量呢。
三、同时实现两个接口的相关方法名的default方法
public interface Interface1{
default void helloWorld() {
System.out.println("hi i'm from Interface1");
}
}
————————————————————————————————————————————————————————————————————
public interface Interface2{
default void helloWorld() {
System.out.println("hi i'm from Interface2");
}
}
——————————————————————————————————————————————————————————————————————
/**
* 实现接口Interface1,Interface2
*/
public class MyImplement implements Interface1,Interface2{
public static void main(String[] args) {
MyImplement myImplement = new MyImplement();
//直接调用helloWorld()方法
myImplement.helloWorld();
}
}
答案肯定无疑:编译器在检查的时候路就会出现报错。
具体如何解决这个问题呢?
当然就是在最新的实现类上重写这个default方法!!!又或者可以直接调用父类的接口中的默认方法!!!
- 方式一:
package defaultVitual;
/**
* 实现接口Interface1,Interface2
*/
public class MyImplement implements Interface1,Interface2{
public static void main(String[] args) {
MyImplement myImplement = new MyImplement();
//直接调用helloWorld()方法
myImplement.helloWorld();
}
@Override
public void helloWorld() {
Interface1.super.helloWorld();
}
}
- 方式二:
package defaultVitual;
/**
* 实现接口Interface1,Interface2
*/
public class MyImplement implements Interface1,Interface2{
public static void main(String[] args) {
MyImplement myImplement = new MyImplement();
//直接调用helloWorld()方法
myImplement.helloWorld();
}
@Override
public void helloWorld() {
System.out.println("hi i'm from MyImplement");
}
}
四、类优先于接口
当实现类同时继承了其他类,并且实现了接口,而其他类的方法和接口的默认方法都存在的时候 。
public class MyImplement2 extends MyImplement implements Interface2{
public static void main(String[] args) {
MyImplement2 myImplement2 = new MyImplement2();
myImplement2.helloWorld();
}
}
会优先执行于被继承的类的方法。
参考相关文章:
(如若有遗漏请联系我)
允许转载,若有侵权,将进行追究
若侵权他人,请联系我,进行删除,谢谢
来自一个写代码的小哥哥
若有错误,请联系我,进行修改
写代码,挣钱,努力,挣钱,run,run,run