在Java中,何时应在接口中使用私有实例方法?


9

从Java 9开始,接口中的方法可以是私有的。私有方法可以是静态方法,也可以是实例方法。由于私有方法只能在接口本身的方法中使用,因此它们的使用仅限于接口其他方法的辅助方法。

Cay S. Horstmann,核心Java第一册-基础

我知道我们可以将通用功能放在私有方法中,而不是公开使用。但是我们可以在这里有两种私有方法:

  1. private
  2. private static

使用private static方法是可以理解的,但是什么时候应该使用private方法呢?我们不在这里处理实例,因为这是一个接口,那么为什么private允许创建方法?我们不是只需要private static方法吗?


接口可以包括其他实例方法调用的方法,但不打算供公共使用。
戴夫·牛顿,

2
尝试private在实现接口的类中调用接口的实例方法。
阿伯拉

1
这样的私有方法可以从接口调用其他方法,因此它们不等同于private static方法或不能被方法替代。
Mark Rotteveel

可能是默认方法
Maurice Perry

Answers:


2

好的,这是实际回答OP的问题的另一种尝试。当需要从私有方法调用接口上的另一个非静态方法时,私有方法不能是静态的。例如,如果下面的私有方法是静态的,则会出现编译错误:

public interface InterfaceWithMethods {
    public default void doSomething() {
        doSomethingCommon();
    }

    public default void doSomethingElse() {
        doSomethingCommon();
    }

    public void actuallyDoSomething();

    private void doSomethingCommon() {
        System.out.println("Do something first.");
        actuallyDoSomething();
    }
}

为什么如此重要?您还可以将每个方法实现为“公共默认值”。问题是关于为什么/出于何种目的选择实现x或y而不是z-而不是如何。
Florian Salihovic

2
@FlorianSalihovic,当您需要从此私有方法中调用另一个方法时,您会选择非静态而不是静态。那不是为什么吗?
jingx

您在问错问题。选择方法的可见性是为了缩小或扩大对象之间如何交互的可能性。重要的是,进行交流的开发人员必须计划/必须/如何使用他们的代码。您可以用静态方法实现所有内容,也可以完全不使用静态方法。这个问题很重要,因为我们需要考虑让其他对象/类访问功能的后果,而这完全是不可访问的。
Florian Salihovic

2
@FlorianSalihovic但是,正如我从人们的评论中了解到的那样,OP并未询问可见性或何时使用静态与非静态,而是询问为什么当似乎可以使用私有静态时,甚至允许在接口上使用非静态私有方法。我的回答提供了一个用例,其中只有非静态方法可以工作。
jingx

3

接口用于定义对象的行为。这意味着所有公开了接口方法。当使用默认方法时,我们可以提供已定义方法的标准实现,从而提供跨类边界的代码重用。

在某些情况下,功能是必需的(也许只是为了在不同的默认方法中重复使用代码),但不应公开,因为它会污染类/对象的名称空间。这是专用默认方法派上用场的地方。私有默认方法的示例可以是工厂,验证或默认状态处理。

package com.company;

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Main {

  public static void main(final String[] args) {
    var messages =
        List.of(
            MessageQueue.newSubject("Message 1"),
            MessageQueue.newTopic("Message 2"),
            MessageQueue.newTopic("Message 3"));
    final MessageQueueAdapter1 queue1 = () -> messages;
    inspectQueue(queue1);
    final MessageQueueAdapter2 queue2 = () -> messages;
    inspectQueue(queue2);
  }

  private static void inspectQueue(final MessageQueue queue) {
    final List<Message> messagesWithSubject = queue.getMessagesWithSubject();
    assert messagesWithSubject.size() == 1 : "expected one message with 'Subject'";
    final List<Message> messagesWithTopic = queue.getMessagesWithTopic();
    assert messagesWithTopic.size() == 2 : "expected two message with 'Topic'";
    assert !queue.getMessages().isEmpty() && 3 == queue.getMessages().size()
        : "expected three messages in total";
  }

  @FunctionalInterface
  interface Message {
    private static boolean isPrefixedBy(final String message, final String prefix) {
      return message != null && !message.isEmpty() && message.startsWith(prefix);
    }

    default boolean hasSubject() {
      return isPrefixedBy(this.getMessage(), MessageQueue.PREFIX_SUBJECT);
    }

    default boolean hasTopic() {
      return isPrefixedBy(this.getMessage(), MessageQueue.PREFIX_TOPIC);
    }

    String getMessage();
  }

  interface MessageQueue {
    String PREFIX_SUBJECT = "Subject: ";

    String PREFIX_TOPIC = "Topic: ";

    private static Message newMessage(final String message) {
      return () -> message;
    }

    static Message newSubject(final String message) {
      return newMessage(PREFIX_SUBJECT + message);
    }

    static Message newTopic(final String message) {
      return newMessage(PREFIX_TOPIC + message);
    }

    List<Message> getMessages();

    List<Message> getMessagesWithSubject();

    List<Message> getMessagesWithTopic();
  }

  @FunctionalInterface
  interface MessageQueueAdapter1 extends MessageQueue {
    private static List<Message> filterBy(
        final List<Message> messages, final Predicate<Message> predicate) {
      return messages.stream().filter(predicate).collect(Collectors.toList());
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithSubject() {
      return filterBy(this.getMessages(), Message::hasSubject);
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithTopic() {
      return filterBy(this.getMessages(), Message::hasTopic);
    }
  }

  @FunctionalInterface
  interface MessageQueueAdapter2 extends MessageQueue {
    private List<Message> filterBy(final Predicate<Message> predicate) {
      return this.getMessages().stream().filter(predicate).collect(Collectors.toList());
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithSubject() {
      return filterBy(Message::hasSubject);
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithTopic() {
      return filterBy(Message::hasTopic);
    }
  }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.