Какая польза от менее строгих модификаторов доступа к членам, чем модификатор доступа к классу?

9

Скажем, у меня есть класс с некоторыми членами, и члены имеют менее ограничительный модификатор доступа, чем сам класс.

Конкретный пример может быть:

package apples;

class A { // package private
    public int foo() { // public (=> less restrictive than *package private*)
        return 42;
    }
}

Насколько я понимаю, модификатор доступа к классу , который является более ограничительным, чем модификатор доступа к элементу , переопределит менее ограничивающие модификаторы доступа к элементу . Таким образом, менее строгий модификатор доступа к элементу не должен иметь никакого эффекта.

  • Правильно ли мое понимание?
    • Если нет, каковы последствия?
  • Какие могут быть веские причины иметь менее строгие модификаторы доступа членов?
  • И, наконец, какой наилучшей практике следовать?

Я также провел некоторые эксперименты, потому что думал, что это может иметь последствия, если я начну передавать ссылки на функции, однако даже тогда модификатор доступа, кажется, не имеет значения.

Ситуация, которую я построил, следующая:

  • apples.Bпредоставляет открытый метод, bla()который возвращает ссылку на apples.A.foo.
  • Затем pizzas.Cзвонит, apples.B.blaчтобы получить ссылку A.fooи звонит.
  • Так A.foo()что не виден напрямую C, а только косвенно доступен черезB.bla()

Я проверил это, и не имеет значения, делаю ли я модификатор доступа foo() пакета закрытым или нет.

package apples;

import java.util.function.IntSupplier;

public class B {
    public IntSupplier getReferenceToAFoo() {
        A aInstance = new A();
        return aInstance::foo;
    }
}
package pizzas;

import apples.B;

import java.util.function.IntSupplier;

public class C {
    private int callAFooIndirectly() {
        B bInstance = new B();
        IntSupplier intsupplier = bInstance.getReferenceToAFoo();
        return intsupplier.getAsInt();
    }

    public static void main(String[] args) {
        C cInstance = new C();

        int i = cInstance.callAFooIndirectly();
        System.out.println(i);
        assert 42 == i;
    }
}
Стефан Д.
источник
2
Наиболее распространенная причина такого дизайна заключается в предоставлении реализаций открытых методов API (таких как интерфейсы или расширенные абстрактные классы) с использованием закрытых классов. Сам JDK изобилует такими классами (например: java.util.Collections.SingletonSet<E>это privateв java.util.Collections).
ernest_k

Ответы:

8

Правильно ли мое понимание?

Да.

Какие могут быть веские причины иметь менее строгие модификаторы доступа членов?

Две причины:

  • Иногда вы реализуете интерфейс; методы интерфейса должны бытьpublic
  • Это облегчает изменение общего доступа вашего класса. Например, если вы отметите все методы, которые вы когда-либо захотите сделать общедоступными public, даже в закрытом для пакета классе, то позже все, что вам нужно сделать, чтобы сделать класс общедоступным, - это добавить publicего в объявление класса.

И, наконец, какой наилучшей практике следовать?

Это вопрос мнения, поэтому он не очень подходит для вопроса или ответа переполнения стека. Делайте то, что кажется разумным для вас и / или вашей команды, и / или делайте то, что говорит вам руководство по стилю вашей команды.

TJ Crowder
источник