Java 接口的静态方法和默认方法
2024-10-08

Java 接口静态方法

接口中的静态方法是指,一些静态工厂方法的实现直接放在类中实现,而不是像以往专门实现接口对应的工厂类,一个简单的例子如下:

public interface StudentFactory {
    static Student fromName(String name) {
        return new Student(name);
    }
}

Java8 以前集合类中的一些静态工厂方法,定义在接口中,然后在用类似名字的类实现,这种为了实现通用方法创建的类叫做伴随类。比如,Path/Paths,前者是接口,后者是对应的工厂类。有了静态方法,这些工厂方法就可以在接口中实现,而不需额外的伴随类。

Java 接口默认方法

Java 接口默认方法是指,在接口声明中,为接口内的方法提供一个默认实现,一个简单的例子如下:

public interface Person {
    default String getName() {
        return getClass().getName() + getClass().hashCode();
    }
}

Person 接口中的 getName() 方法提供一个默认实现,根据 Java 标准,接口中的默认方法必须用 default 修饰。

乍看起来这样写是没有什么意义的,因为如果一个类实现了 Person 接口,必须重新实现里面的方法,但是在特定的情形下,这个机制非常有用。

一个重要的目的是为了接口演化。一般来说,jdk 升级等较大规模的升级过程中,可能会给某些接口增加一些新的方法。由于没有默认方法的情况下,非抽象类实现一个接口意味着必须实现接口中的所有方法,为了通过编译,必须重构所有实现该接口的类,这是非常不友好的。用默认方法可以方便的解决这类问题,因为默认方法可以不在类中重新实现。

另一个目的是允许按需实现接口中的方法。在某些情形下,比如一个事务处理的接口,包含 preProcess() , afterProcess() 两个方法。但是很多情形下,只需要按照需求实现其中的一个处理逻辑,如果没有默认方法,我们必须实现这两个方法。而有了 默认方法后,只需要两个方法在接口中默认为空方法,那么我们就可以按需实现自己的处理逻辑。

Java 默认方法冲突

由于默认方法在接口中包含了方法的默认实现,所以可能会和超类或者其他接口中的实现冲突,有两种类型的冲突。

第一种是指一个类的超类中的方法和接口中的默认方法同名且同参数类型,这种情况下,超类中的方法具有更高优先级,接口中的方法会被忽略。此情形下,相当于语言自动解决了冲突,无需程序员手动解决。

第二种是指一个类实现了多个接口,这些接口中包含同名同参数类型的方法,并且至少一个提供了默认实现,那么就需要程序员手动在类中重新实现这个方法以解决冲突。

需要注意的是,不要假设两个接口中的同名同类型的方法,一个有默认实现,一个没有的时候,类中会自动引用那个默认实现。Java 语言为了语义一致,只要有一个接口中提供了默认实现,就必须手动解决冲突。