在Java 9中,接口可以包含私有方法(包括静态私有方法和实例私有方法)。这允许接口的设计者创建一些辅助方法,这些方法只能被接口中的其他方法所使用,而不能被实现该接口的类直接访问。
Java7
Java7及之前 ,接口中只允许两种类型的变量与方法:
- 常量
- 抽象方法
我们来看看一个示例,有个List接口:
package com.morris.java9;
public interface List7 {
String author = "morris";
void add(Object o);
Object get(int index);
int size();
boolean isEmpty();
}
由于List有很多实现类,比如ArrayList、LinkedList,所以我们使用一个抽象类来实现这些实现类的公共逻辑:
package com.morris.java9;
public abstract class AbstractList7 implements List7 {
@Override
public boolean isEmpty() {
return 0 == size();
}
}
List的一个实现类ArrayList:
package com.morris.java9;
public class ArrayList7 extends AbstractList7 {
@Override
public void add(Object o) {
}
@Override
public Object get(int index) {
return null;
}
@Override
public int size() {
return 0;
}
}
可以看到Java7中接口是非常简单的,接口中声明的变量都是public
的常量,不需要显示指定public
关键字。接口中的方法都是public abstract
,不需要显示的指定public abstract
关键字。
Java8
Java8中对接口作出了一些改变,接口中可以具有以下类型的变量和方法
- 常量
- 抽象方法
- 默认方法
- 静态方法
我们将上面的范例改改,使用Java8的特性:
package com.morris.java9;
public interface List8 {
String author = "morris";
void add(Object o);
Object get(int index);
int size();
default boolean isEmpty() {
return 0 == size();
}
}
因为Java8的接口中的方法可以有默认实现,也就是使用default关键字修饰的方法,可以将AbstractList7中各个实现类的公共逻辑迁移到接口中,这样AbstractList7这种抽象类就可以不用存在了。
另外在接口中如果加了一个方法,所有的实现类都需要实现这个方法,而有了默认方法之后,接口的所有实现类可以有选择的重写这个默认方法。
所以,类实现某个接口就比较简单了,可以有选择性的实现部分方法。
Java8中的接口可以添加静态方法,这样就可以把接口当成工具类来实现,不需要像以前一样创建一个工具类,然后将工具栏的构造方法设置为私有的。
集合工具类以前的写法:
package com.morris.java9;
import java.util.Collection;
import java.util.Objects;
public class CollUtil7 {
private CollUtil7() {
}
public static boolean isEmpty(Collection<Object> list) {
return Objects.isNull(list) || list.isEmpty();
}
}
使用接口的静态方法实现工具类:
package com.morris.java9;
import java.util.Collection;
import java.util.Objects;
public interface CollUtil8 {
static boolean isEmpty(Collection<Object> list) {
return Objects.isNull(list) || list.isEmpty();
}
}
Java9
Java9中的接口,可以具有以下类型的变量和方法:
- 常量
- 抽象方法
- 默认方法
- 静态方法
- 私有静态方法
- 私有方法
在Java9中,接口可以包含私有方法(包括静态私有方法和实例私有方法)。这允许接口的设计者创建一些辅助方法,这些方法只能被接口中的其他方法所使用,而不能被实现该接口的类直接访问。
私有方法可以是静态的,也可以是非静态的(即实例方法)。
静态私有方法:这些方法只与接口本身关联,而不是与接口的任何特定实例关联。它们通常用于辅助实现接口中的默认方法或静态方法。
public interface MyInterface {
static void staticMethod() {
// ...
staticPrivateMethod();
}
private static void staticPrivateMethod() {
// 这是一个私有静态方法
}
}
实例私有方法:这些方法与接口的实例关联,并可以用于实现接口中的默认方法。它们不能直接在实现该接口的类的实例上调用。
public interface MyInterface {
default void defaultMethod() {
// ...
instancePrivateMethod();
}
private void instancePrivateMethod() {
// 这是一个私有实例方法
}
}
使用私有方法的主要好处是,它们可以帮助组织代码,隐藏实现细节,并防止其他类直接访问这些方法。这有助于保持接口的简洁性,同时允许在接口内部实现更复杂的逻辑。
需要注意的是,尽管接口可以有私有方法,但它们仍然不能有任何状态(即实例字段)。接口仍然只能定义行为(即方法),而不能定义状态。
以下是私有方法在接口中的一些使用场景:
-
代码复用和封装:如果一个接口中有多个默认方法或静态方法需要执行相同的逻辑片段,你可以将这些重复的代码提取到一个私有方法中。这样,当需要修改或扩展这部分逻辑时,只需在一个地方进行修改,而不是多个地方。
-
实现逻辑细节隐藏:通过将一些实现细节封装在私有方法中,你可以保护这些逻辑不被接口的使用者直接访问或调用。这有助于保持接口的公共API的清晰和简洁,同时允许在接口内部实现更复杂的逻辑。
-
辅助方法:有时候,实现一个默认方法可能需要多个步骤或多个辅助函数。这些辅助函数可以作为私有方法定义在接口中,而不是将它们作为公共方法暴露给接口的使用者。
-
静态辅助方法:私有静态方法可以在接口中用于辅助实现其他静态方法。这些方法通常用于计算或转换值,而不涉及任何与接口实例相关的状态。
-
避免与实现类的方法冲突:如果接口中的公共方法可能会与实现类中的方法名称冲突,使用私有方法可以避免这种冲突。实现类可以自由地实现或覆盖与接口中的私有方法同名的方法,而不会与接口中的方法产生混淆。
下面是一个示例,演示了如何在接口中使用私有方法:
public interface Calculator {
int add(int a, int b);
int subtract(int a, int b);
default int multiply(int a, int b) {
return a * b;
}
default int divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("Divisor cannot be zero");
}
return a / b;
}
// 私有方法用于检查输入参数是否有效
private static boolean isValidInput(int a, int b) {
return a >= 0 && b >= 0;
}
// 另一个默认方法,使用私有辅助方法
default int safeAdd(int a, int b) {
if (!isValidInput(a, b)) {
throw new IllegalArgumentException("Input values must be non-negative");
}
return add(a, b);
}
}
在这个示例中,isValidInput
是一个私有静态方法,用于检查输入参数是否有效。safeAdd
是一个默认方法,它使用 isValidInput
方法来验证输入,并在必要时抛出异常。这样,safeAdd
方法的实现可以保持简洁,而验证逻辑被封装在了一个私有方法中。