在Java中,什么时候应该在接口中使用私有示例方法?

h9vpoimq  于 5个月前  发布在  Java
关注(0)|答案(3)|浏览(45)

从Java 9开始,接口中的方法可以是私有的。私有方法可以是静态的或示例方法。由于私有方法只能在接口本身的方法中使用,因此它们的用途仅限于作为接口的其他方法的帮助器方法。

Cay S. Horstmann,Core Java Volume I - Fundamentals

我知道我们可以把公共功能放在private方法中,而不是让它对public访问。但是我们可以在这里有两种private方法:
1.第一个月

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

3wabscal1#

接口用于定义对象的行为。这意味着接口的所有方法都是公开的。当使用默认方法时,我们可以提供定义方法的标准实现,提供跨类边界的代码重用。
在某些情况下,功能是必需的(也许只是为了在不同的 *default方法 * 中重用代码),但不应该暴露,因为它会污染类/对象的命名空间。这就是 *private default方法 * 派上用场的地方。例如private default方法可以是工厂,验证或默认状态处理。

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);
    }
  }
}

字符串

sc4hvdpw

sc4hvdpw2#

好了,又一次尝试实际回答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();
    }
}

字符串

stszievb

stszievb3#

我在阅读OCP Java 17考试指导书时也遇到了同样的问题,这里是我在阅读时意识到的一些见解。
default & private非静态方法可以调用抽象方法。(接口中存在private非静态方法的原因。它与实现类的示例相关联。)
私有静态方法不能静态引用非静态抽象方法。(注意抽象不能和静态一起使用。)

interface PrivateMethodEx {
    void abstractMethod();
    default void defaultMethod() {
        anotherPrivateMethod();
        anotherPrivateStaticMethod();
        abstractMethod();
    }
    private void privateMethod() {};
    private static void privateStaticMethod() {};
    private void anotherPrivateMethod() {
        privateMethod();
        privateStaticMethod();
        abstractMethod();
    }
    private static void anotherPrivateStaticMethod() {
        // privateMethod();  // Compile error. Cannot make static reference to non-static method.
        privateStaticMethod();
        // abstractMethod();  // Compile error. Cannot make static reference to non-static method.
    }
}

字符串

相关问题