@Override,在接口中使用默认方法

@Override, with default methods in interfaces

我一直在阅读有关在 Java 中使用 @Override 的一些问题。 (例:this one on override and this one on default methods, and obviously the documentations)不过,我还是一头雾水

当 class 需要使用该接口中的所有行为时,我被教导要始终使用和实现该接口。我明白了。但是正如我被教导的那样,你会做这样的事情(部分取自文档):

public interface TimeClient {
    void setTime(int hour, int minute, int second);
}

然后由class实现。

public class TestSimpleTimeClient implements TimeClient {
    public static void main(String[] args) {
    }

    @Override
    public void setTime(int hour, int minute, int second) {
         System.out.println(hour + " " + minute + " " +second);
    }
}

让我烦恼的是接口中方法的实现。它什么都不做,它只是被声明为一个接受参数但不做任何其他事情的方法。然后你采用该方法并在实现该接口的 class 中覆盖它。

我知道这是 "force" classes 实现方法的一种方法,但我看不出这在某些特定用例中有何用处。

假设我有一个由几个 classes 实现的接口。我希望这些 class 中的大多数共享该方法的相同实现,但不是全部。合乎逻辑且字符高效的方法是有一种说法:这些 classes 在界面中采用默认方法,但这些 classes 覆盖默认方法。我该怎么做呢?覆盖该方法的方法是否应该仅实现它,而仅将默认方法作为一个整体使用的方法是否应该扩展它?如果您只希望接口中的特定方法具有这种行为怎么办?

The thing that bugs me is the implementation of the method in the interface. It doesn't do anything, it's only declared as a method that take arguments but doesn't do anything else.

那不是 "implementation of the method in the interface"。那只是一个接口方法声明。在编程中,术语很重要。接口往往没有任何实现。 (除非你在谈论 Java 8 的默认接口方法,但从你的问题的其余部分来看,不清楚你是否知道它们的存在。)

I understand that this is a way to "force" classes to implement a class

A class 无法实现 class。 class 扩展了 class。但是 class 实现了一个接口。在编程中,术语很重要。

这不仅仅是一种强制 classes 提供实现的方法。这也是调用者能够调用接口方法而无需了解实现它的 class 的一种方式。

but I don't see how this is useful in some specific use cases.

嗯,比如Collection<T>接口,还有contains()方法,它是由无数classes实现的,其中ArrayList<T>LinkedList<T>HashSet<T>BoundedBlockingQueue<T>,依此类推。您的代码可能如下所示:

boolean hasPekingese( Collection<Animal> animals )
{
    return animals.contains( AllOfMyAnimals.PEKINGESE );
}

请注意 hasPekingese() 方法如何不必知道实施 Collection<Animal> 的确切 class。这意味着您可以从 class 调用 hasPekingese() 将其动物保存在 ArrayList<Animal> 中,您还可以从 class 调用 hasPekingese() 将其保存BoundedBlockingQueue<Animal> 中的动物。方法hasPekingese()不知道,也不关心

Let's say I have an interface that's shared by a couple of classes.

不清楚您所说的 "shared" 是什么意思。你是说 "implemented" 吗?在编程中,术语是最重要的。

I want most of these classes to share the same implementation of the method, but not all. The logical, and character-efficient way would be to have a way to say: these classes take the default method in the interface, but these classes override the default method. How would I go about doing that?

有很多方法可以做到这一点,最常见的是让其中一些 classes 扩展一些公共基础 class,它提供了你的方法的公共实现,这样派生的 classes 继承了这个方法,所以他们不必实现它。 classes 的其余部分不扩展该公共基础 class,因此它们中的每一个都必须提供该方法的自己的实现。

Should the one that overrides the method only implement it, whereas the ones that simply use the default method as a whole extend it?

不清楚。另外,请不要称它为 "default method",因为 as of Java 8 "default method" 是一个具有非常特定含义的术语,虽然它与此讨论相关,但它是不同的从您使用它的意义上来说。

And what if you only want this behaviour for a specific method in an interface?

如果派生 class 希望该方法以不同的方式工作,它可能会重新覆盖它。或者,您可能有两个不同的基础 classes,一个以某种方式实现该方法,另一个以不同的方式实现它,因此您派生的 classes 的一半扩展了第一个基础 class,而你派生的另一半 classes 扩展了第二个基数 class.

接口就像 API。当某些提供者为您提供类似 List 的接口时,您无需考虑它是 ArrayList 还是其他实现,您只知道可以使用该对象做什么。为什么?因为当你给一个接口的时候,你可以在以后改变实现,不用担心通过接口使用对象的其他部分代码需要改变。

我想您正在考虑应该将某些行为插入当前 class 的事情。这些东西在其他编程语言中可以称为 Traits,在另一种语言中你有多重继承。如果你想要一些传播到你的 classes 的实现逻辑,你应该在 java 中使用具有适当层次结构的抽象 classes。请记住,您可以使用继承或组合来扩展 classes (open-closed principle)。

接口中的默认方法 (Java 8) 可能很棘手,因为它们无法更改对象的状态。它们可能是一些仅适用于本地和静态上下文的存根或数学方程式。