Abstact类和接口之间的区别
- Java 8中的抽象类与接口
- 概念差异:
Java 8中的接口默认方法
- 什么是默认方法?
- 使用默认方法解决了ForEach方法编译错误
- 默认方法和多重继承歧义问题
- 有关Java接口默认方法的要点:
Java接口静态方法
- Java接口静态方法,代码示例,静态方法与默认方法
- 有关Java接口静态方法的要点:
Java功能接口
Java 8中的抽象类与接口
Java 8接口更改包括接口中的静态方法和默认方法。在Java 8之前,接口中只能有方法声明。但是从Java 8开始,我们可以在接口中使用默认方法和静态方法。
引入默认方法后,接口和抽象类似乎相同。但是,它们仍然是Java 8中的不同概念。
抽象类可以定义构造函数。它们更加结构化,并且可以具有与之关联的状态。相比之下,默认方法只能在调用其他接口方法方面实现,而无需参考特定实现的状态。因此,两者用于不同目的以及在两者之间进行选择实际上取决于场景上下文。
概念差异:
抽象类对于接口的骨架(即部分)实现有效,但在没有匹配接口的情况下不应存在。
因此,当有效地将抽象类简化为低可见性的接口的基本实现时,默认方法是否也可以消除这种缺陷?决定:不!实现接口几乎总是需要某些或所有默认方法所缺少的类构建工具。而且,如果某些界面没有,那显然是一种特殊情况,这不会使您误入歧途。
Java 8中的接口默认方法
Java 8引入了“ 默认方法 ”或(Defender方法)新功能,该功能使开发人员可以在不破坏现有接口实现的情况下向接口添加新方法。它提供了灵活性,允许Interface定义实现,在具体的Class无法为该方法提供实现的情况下,它将默认使用该实现。
让我们考虑一个小示例,以了解其工作原理:
public interface OldInterface {
public void existingMethod();
default public void newDefaultMethod() {
System.out.println("New default method"
+ " is added in interface");
}
}
以下类将在Java JDK 8中成功编译,
public class OldInterfaceImpl implements OldInterface {
public void existingMethod() {
// existing implementation is here…
}
}
如果您创建OldInterfaceImpl的实例:
OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod();
默认方法永远不会是最终方法,无法同步,也不能覆盖Object的方法。它们始终是公共的,这严重限制了编写简短且可重用方法的能力。
可以将默认方法提供给接口,而不会影响实现类,因为它包括实现。如果在接口中通过实现定义了每个添加的方法,则不会影响实现类。实现类可以覆盖接口提供的默认实现。
默认方法可以在不破坏这些接口的较早实现的情况下向现有接口添加新功能。
当我们扩展包含默认方法的接口时,我们可以执行以下操作:
- 不覆盖默认方法,并将继承默认方法。
- 覆盖默认方法,类似于我们在子类中覆盖的其他方法。
- 将默认方法重新声明为抽象,这将迫使子类重写它。
使用默认方法解决了ForEach方法编译错误
对于Java 8,JDK集合已得到扩展,并且forEach方法已添加到整个集合(与lambda结合使用)。使用传统方式,代码如下所示,
public interface Iterable<T> {
public void forEach(Consumer<? super T> consumer);
}
由于此结果导致每个实现的Class都带有编译错误,因此将默认方法与所需的实现一起添加,以便不应该更改现有的实现。
以下是使用默认方法的Iterable接口,
public interface Iterable<T> {
public default void forEach(Consumer
<? super T> consumer) {
for (T t : this) {
consumer.accept(t);
}
}
}
在不破坏实现类的情况下,已使用相同的机制在JDK接口中添加Stream。
默认方法和多重继承歧义问题
由于java类可以实现多个接口,并且每个接口都可以定义具有相同方法签名的默认方法,因此,继承的方法可能会相互冲突。
考虑下面的例子,
public interface InterfaceA {
default void defaultMethod(){
System.out.println("Interface A default method");
}
}
public interface InterfaceB {
default void defaultMethod(){
System.out.println("Interface B default method");
}
}
public class Impl implements InterfaceA, InterfaceB {
}
上面的代码将无法编译,并出现以下错误,
java:Impl类从InterfaceA和InterfaceB类型继承defaultMethod()的不相关默认值
为了修复此类,我们需要提供默认的方法实现:
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
}
}
此外,如果我们要调用超级接口提供的默认实现而不是我们自己的实现,则可以执行以下操作:
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
// existing code here..
InterfaceA.super.defaultMethod();
}
}
作为新方法的一部分,我们可以选择任何默认实现或两者。
有关Java接口默认方法的要点:
- Java接口默认方法将帮助我们扩展接口,而不必担心破坏实现类。
- Java接口默认方法缩小了接口和抽象类之间的差异。
- Java 8接口的默认方法将帮助我们避免使用实用程序类,例如可以在接口本身中提供所有Collections类的方法。
- Java接口默认方法将帮助我们删除基本实现类,我们可以提供默认实现,而实现类可以选择要覆盖的类。
- 在接口中引入默认方法的主要原因之一是增强Java 8中的Collections API以支持lambda表达式。
- 如果层次结构中的任何类都具有具有相同签名的方法,则默认方法将变得无关紧要。缺省方法不能覆盖java.lang.Object中的方法。推理非常简单,这是因为Object是所有java类的基类。因此,即使我们将Object类方法定义为接口中的默认方法,也将是无用的,因为将始终使用Object类方法。这就是为什么要避免混淆的原因,我们不能使用覆盖Object类方法的默认方法。
- Java接口默认方法也称为Defender方法或虚拟扩展方法。
资源链接:
- 使用Java 8中的默认方法与Abstract类进行接口
- JDK 8时代的抽象类与接口
- 通过虚拟扩展方法进行接口演变
Java接口静态方法
Java接口静态方法,代码示例,静态方法与默认方法
Java接口静态方法与默认方法类似,不同之处在于我们无法在实现类中覆盖它们。如果实现类中的实现不佳,此功能可帮助我们避免不良结果。让我们通过一个简单的示例对此进行研究。
public interface MyData {
default void print(String str) {
if (!isNull(str))
System.out.println("MyData Print::" + str);
}
static boolean isNull(String str) {
System.out.println("Interface Null Check");
return str == null ? true : "".equals(str) ? true : false;
}
}
现在,让我们看一下具有isNull()方法且实现不佳的实现类。
public class MyDataImpl implements MyData {
public boolean isNull(String str) {
System.out.println("Impl Null Check");
return str == null ? true : false;
}
public static void main(String args[]){
MyDataImpl obj = new MyDataImpl();
obj.print("");
obj.isNull("abc");
}
}
请注意,isNull(String str)是一个简单的类方法,它没有覆盖接口方法。例如,如果将@Override批注添加到isNull()方法,则将导致编译器错误。
现在,当我们运行应用程序时,我们将得到以下输出。
接口空检查
Impl空检查
如果将接口方法从静态设置为默认值,则会得到以下输出。
Impl空检查
MyData打印::
Impl空检查
Java接口静态方法仅对接口方法可见,如果我们从MyDataImpl类中删除isNull()方法,则无法将其用于MyDataImpl对象。但是,像其他静态方法一样,我们可以使用带有类名的接口静态方法。例如,有效的语句将是:
boolean result = MyData.isNull("abc");
有关Java接口静态方法的要点:
- Java接口静态方法是接口的一部分,我们不能将其用于实现类对象。
- Java接口静态方法非常适合提供实用程序方法,例如null检查,集合排序等。
- Java接口静态方法通过不允许实现类覆盖它们来帮助我们提供安全性。
- 我们无法为Object类方法定义接口静态方法,我们将得到编译器错误,因为“此静态方法无法从Object隐藏实例方法”。这是因为在Java中是不允许的,因为Object是所有类的基类,并且我们不能有一个类级别的静态方法和另一个具有相同签名的实例方法。
- 我们可以使用java接口静态方法删除实用程序类(例如Collections),并将其所有静态方法移动到相应的接口,这将很容易找到和使用。
Java功能接口
在结束本文之前,我想简要介绍一下Functional接口。具有唯一一种抽象方法的接口称为功能接口。
@FunctionalInterface
引入了新的注释,以将接口标记为“功能接口”。@FunctionalInterface
注释是一种避免在功能接口中意外添加抽象方法的工具。这是可选的,但是使用它是一个好习惯。
功能接口是Java 8期待已久且广受欢迎的功能,因为它使我们能够使用lambda表达式实例化它们。添加了带有功能接口束的新程序包java.util.function,以提供lambda表达式和方法引用的目标类型。在以后的文章中,我们将研究功能接口和lambda表达式。
资源位置:
- Java 8接口更改–静态方法,默认方法