Java 8中接口中的静态方法有什么作用?

28

为什么Java 8支持静态方法?在下面的代码中,main方法中两行代码有什么区别?

package sample;
public class A {
    public static void doSomething()
    {
        System.out.println("Make A do something!");
    }
}

public interface I {
    public static void doSomething()
    {
        System.out.println("Make I do something!");
    }
}

public class B {
    public static void main(String[] args) {
        A.doSomething(); //difference between this
        I.doSomething(); //and this
    }
}

就像我们上面可以看到的那样,在B中甚至没有实现I。如果我们可以在另一个类中编写相同的静态方法并调用它,那么在接口中拥有静态方法会有什么用处呢?除了模块化之外,它是否被引入了其他用途? 而通过模块化,我指的是以下内容:

public interface Singable {
    public void sing();
    public static String getDefaultScale()
    {
        return "A minor";
    }
}

只是为了将相似的方法放在一起。


4
这应该可以解释清楚:https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html - Marvin
1
没有区别。 - eliaspr
1
静态方法提供默认方法,实现类不需要覆盖它。如果方法逻辑在所有实现中都被复制,这是特别有用的。例如,PopSong和RockSong类可以实现它,并且两者都将具有默认音阶A小调。 - Arunav Sanyal
@Marvin 所以它们被用作辅助方法和模块化?在Java 8之前,如何实现相同类型的功能的辅助方法? - Tarun Mohandas
7
接口中定义静态方法有什么用处呢?我们为什么不能在其他类中编写相同的静态方法并调用它呢?- 如果有了接口中的静态方法,现在就不必再特别编写一个类来保存这些静态方法了。 - user2357112
1
@Arunav Sanyal,您混淆了静态方法和默认方法。 - nicktalbot
2个回答

35
过去,如果你有一个名为 Foo 的接口并希望将所有与接口相关的工具或工厂方法分组,那么你需要创建一个单独的工具类 FooUtils 并将所有东西存储在那里。
这些类除了名称外没有任何共同点。此外,工具类需要被设为 final 并拥有一个私有构造函数以禁止不必要的使用。
现在,由于接口静态方法的存在,您可以将所有内容放在一个地方而不需要创建任何额外的类。
同时也很重要不要忘记所有良好的实践,不要盲目地把一切都扔到一个接口类中 - 正如在这个答案中指出的那样。

1
@GrzegorzPiwowarek CollectorsStreamSupportSpliterators并不是多余的类;在接口中必须有一行代码是过多的。 - Eugene
1
@Eugene 当然,总会有一些例外情况,这是一个很好的例子。把所有东西都放在一个类里面会导致难以管理的混乱。 - Grzegorz Piwowarek

15
主要有两个原因使接口内部存在静态方法:其一是为了创建这些接口的实例(代码明确在哪里),例如 Predicate::isEqual 可以根据提供的对象创建一个 Predicate;或者 Comparator::comparing 等等。其二是通用工具方法适用于所有这些类型,例如 Stream::of

但是,接口必须清晰,不应该在 API 中创建额外的混乱。即使 JDK 代码中也有Collectors - 静态工厂方法,但同时也有一个Collector接口。这些方法可以合并到Collector接口中,但这会使接口比它必须的还要臃肿。


请您详细说明“创建实例”的用法?我认为我们可以选择使用Arrays.stream来创建实例,而不是使用Stream.of。使用Stream.of的原因或多或少归结于将相关的实用方法分组在一个命名空间中,这是您的第二个用例。或者我是否误解了您的示例? - wlnirvana
@wlnirvana,你认为Stream::of在内部做了什么? - Eugene
它在内部使用Arrays.stream。这正是我的观点:你的第一个原因最终归结为你的第二个原因。在这种情况下,Stream.of只是一个包装器。对我来说,这个包装器的动机似乎更多地是“适用于所有这些类型的实用方法”而不是“创建这些接口的实例”。 - wlnirvana
@wlnirvana 确实。我现在明白你的观点了。我已经编辑了答案,感谢你的建议。 - Eugene
我现在也明白你的观点了。感谢你提供这个好例子。 - wlnirvana

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接