Java 8接口更改–静态方法,默认方法

时间:2020-02-23 14:36:18  来源:igfitidea点击:

Java 8接口更改包括接口中的静态方法和默认方法。
在Java 8之前,接口中只能有方法声明。
但是从Java 8开始,我们可以在接口中使用默认方法和静态方法。

Java 8接口

设计接口一直是一项艰巨的工作,因为如果我们想在接口中添加其他方法,则将需要对所有实现类进行更改。
随着接口的老化,实现接口的类的数量可能会增加到无法扩展接口的程度。
这就是为什么在设计应用程序时,大多数框架都提供一个基本的实现类,然后我们对其进行扩展并覆盖适用于我们的应用程序的方法。

让我们研究一下默认接口方法和静态接口方法,以及它们在Java 8接口更改中引入的原因。

Java接口默认方法

为了在Java接口中创建默认方法,我们需要在方法签名中使用" default"关键字。
例如,

package com.theitroad.java8.defaultmethod;

public interface Interface1 {

	void method1(String str);
	
	default void log(String str){
		System.out.println("I1 logging::"+str);
	}
}

注意log(String str)是Interface1中的默认方法。
现在,当一个类将实现Interface1时,就不必为接口的默认方法提供实现。
此功能将帮助我们使用其他方法扩展接口,我们所需要的只是提供默认的实现。

假设我们还有一个使用以下方法的界面:

package com.theitroad.java8.defaultmethod;

public interface Interface2 {

	void method2();
	
	default void log(String str){
		System.out.println("I2 logging::"+str);
	}

}

我们知道Java不允许我们扩展多个类,因为它会导致"钻石问题",编译器无法决定要使用哪种超类方法。
使用默认方法,接口也会出现菱形问题。
因为如果一个类同时实现了Interface1和Interface2并且没有实现通用的默认方法,则编译器无法决定选择哪个方法。

扩展多个接口是Java不可或者缺的一部分,您可以在核心Java类以及大多数企业应用程序和框架中找到它。
因此,为确保不会在接口中发生此问题,必须为常见的默认接口方法提供实现。
因此,如果一个类同时实现上述两个接口,则必须为log()方法提供实现,否则编译器将抛出编译时错误。

同时实现Interface1Interface2的简单类将是:

package com.theitroad.java8.defaultmethod;

public class MyClass implements Interface1, Interface2 {

	@Override
	public void method2() {
	}

	@Override
	public void method1(String str) {
	}

	@Override
	public void log(String str){
		System.out.println("MyClass logging::"+str);
		Interface1.print("abc");
	}
}

有关Java接口默认方法的要点:

  • Java接口默认方法将帮助我们扩展接口,而不必担心破坏实现类。

  • Java接口默认方法缩小了接口和抽象类之间的差异。

  • Java 8接口的默认方法将帮助我们避免使用实用程序类,例如可以在接口本身中提供所有Collections类的方法。

  • Java接口默认方法将帮助我们删除基本实现类,我们可以提供默认实现,而实现类可以选择覆盖哪个实现。

  • 在接口中引入默认方法的主要原因之一是增强Java 8中的Collections API以支持lambda表达式。

  • 如果层次结构中的任何类都具有具有相同签名的方法,则默认方法将变得无关紧要。
    默认方法不能覆盖java.lang.Object中的方法。
    推理非常简单,这是因为Object是所有java类的基类。
    因此,即使我们将Object类方法定义为接口中的默认方法,也将是无用的,因为将始终使用Object类方法。
    因此,为了避免混淆,我们不能使用覆盖Object类方法的默认方法。

  • Java接口默认方法也称为Defender方法或者虚拟扩展方法。

Java接口静态方法

Java接口静态方法与默认方法类似,不同之处在于我们无法在实现类中覆盖它们。
如果实现类中的实现不佳,此功能可帮助我们避免不良结果。
让我们通过一个简单的示例对此进行研究。

package com.theitroad.java8.staticmethod;

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()方法的实现不佳。

package com.theitroad.java8.staticmethod;

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()方法,则将导致编译器错误。

现在,当我们运行应用程序时,我们将获得以下输出。

Interface Null Check
Impl Null Check

如果将接口方法从静态设置为默认值,则会得到以下输出。

Impl Null Check
MyData Print::
Impl Null Check

Java接口静态方法仅对接口方法可见,如果我们从MyDataImpl类中删除isNull()方法,我们将无法将其用于MyDataImpl对象。
但是,像其他静态方法一样,我们可以使用带有类名的接口静态方法。
例如,有效的语句将是:

boolean result = MyData.isNull("abc");

关于Java接口静态方法的要点:

  • Java接口静态方法是接口的一部分,我们不能将其用于实现类对象。

  • Java接口静态方法非常适合提供实用程序方法,例如null检查,集合排序等。

  • Java接口静态方法通过不允许实现类覆盖它们来帮助我们提供安全性。

  • 我们无法为Object类方法定义接口静态方法,因为"此静态方法无法从Object隐藏实例方法",因此会出现编译器错误。
    这是因为在Java中是不允许的,因为Object是所有类的基类,并且我们不能拥有一个具有类签名的静态方法和另一个实例方法。

  • 我们可以使用java接口静态方法来删除实用程序类(例如Collections),并将其所有静态方法移动到相应的接口,这将很容易找到和使用。

Java功能接口

在结束本文之前,我想简要介绍一下Functional接口。
具有唯一一种抽象方法的接口称为功能接口。

引入了新的注释@FunctionalInterface,以将接口标记为Functional Interface。
@FunctionalInterface注释是一种避免在功能接口中意外添加抽象方法的工具。
这是可选的,但是使用起来很好。

功能接口是人们期待已久的Java 8的功能,因为它使我们能够使用lambda表达式实例化它们。
添加了带有功能接口束的新程序包" java.util.function",以提供lambda表达式和方法引用的目标类型。