Java8 接口

前言

Java 8已经推出相当长一段时间了,其中,接口部分有一些变化。我们来研究下它。

问题

我们知道,对于一个接口,如果我们声明好后,如果再想对其增加新的方法是困难的,因为我们要改变所有其实现类,也就是每个实现类都要对其新方法进行实现。如下图:

在这里插入图片描述

这显然是不现实的,如果我们直接把方法写在实现类里,接口中没有此方法,就破坏了我们的多态性。

对于某些已经发布的应用,无论哪种做法都是比较繁重且不被推荐的。

接口默认实现

还好,Java大神们已经意识到了这个问题,于是在Java8中,引入了对接口的默认方法实现。

什么是默认方法实现呢?

简单来说,就是允许接口定义默认方法,在接口中需要有方法体的具体实现,实现类默认继承该方法(如果不重写默认方法的话)。同时为区分默认方法,默认方法在接口中采用default关键字标明。如下图:

在这里插入图片描述

这样,如果我们新增一个接口方法(对于已经发布的接口),可以使用默认实现,就不会出现我们上述的问题。

思考

你一定会说,这和抽象类有什么区别呢?

当然还是有区别的,Java8以后,接口和抽象类的几点总结如下:

在这里插入图片描述

新的问题

接口引入了默认方法后,就会有新的问题,好在Java已经替我们解决了,我们来看下。

情况一

public interface A {
	default void doSomething(){
		System.out.println("Interface A");
	}
}
public interface B extends A{
	default void doSomething(){
		System.out.println("Interface B");
	}
}
public class C implements A, B {
	public static void main(String[] args) {
		new C().doSomething();
	}
}

结果:输出 Interface B

情况二

public class D implements A {
}
public class C extends D implements A, B {
	public static void main(String[] args) {
		new C().doSomething();
	}
}

结果:输出 Interface B

情况三

如果D是这样呢?

public class D implements A {
	public void doSomething(){
		System.out.println("Class D");
	}
}

结果:输出Class D

如果D不对doSomething提供实现(D为抽象的类),则C需要为doSomething提供实现。

情况四

如果B接口不在继承A接口。如下:

public interface A {
	default void doSomething(){
		System.out.println("Interface A");
	}
}
public interface B{
	default void doSomething(){
		System.out.println("Interface B");
	}
}

那么我们C类必须为doSomething提供实现,当然我们可以具体制定使用哪个接口的doSomething方法,如下:

public class C implements A, B {
	@Override
	public void doSomething() {
		B.super.doSomething();
	}
}

情况五

如果两个函数不一样但差距很小呢?如下:

public interface A {
	default int doSomething(){
		return 100;
	}
}
public interface B{
	default long doSomething(){
		return 200;
	}
}
public class C implements A, B {
	public static void main(String[] args) {
		new C().doSomething();
	}
}

在IDEA里我们可以看到,类C是无法编译的,这是不被允许的。

情况六

public interface A {
	default void doSomething(){
		System.out.println("Interface A");
	}
}
public interface B extends A{
}
public interface C extends A{
}
public class D implements B,C {
	public static void main(String[] args) {
		new D().doSomething();
	}
}

输出结果Interface A

因为只有A声明了一个默认方法,这个接口是D的父接口,故输出Interface A。如果B也提供了一个默认方法,签名和A一致,那么编译器会选择B的默认方法,如果B添加一个相同签名的抽象方法,则D需要为其提供实现,如果B,C都有相同签名的默认方法doSomething,则会出现冲突,需要我们为doSomething提供实现或者指定使用B,C中的哪个方法。

结论

解决问题的三条规则:

如果一个类使用相同的函数签名从多个地方(比如另一个类或者接口)继承了方法,通过三条规则可进行判断。

  1. 类中的方法优先级最高。类或者父类中声明的方法优先级高于任何声明为默认方法的优先级。

  2. 如果无法依据第一条判断,那么子接口的优先级更高:函数签名相同时,优先选择拥有最具体实现的默认方法的接口,及如果B继承了A,那么B就比A更加具体。

  3. 最后,如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法,显式地选择使用哪一个默认方法的实现。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值