«1. Обзор

В этой быстрой статье мы подробно рассмотрим модификатор public и обсудим, когда и как его использовать с классами и членами.

Кроме того, мы проиллюстрируем недостатки использования общедоступных полей данных.

Общий обзор модификаторов доступа можно найти в нашей статье о модификаторах доступа в Java.

2. Когда использовать модификатор Public Access

Общедоступные классы и интерфейсы, наряду с общедоступными членами, определяют API. Это та часть нашего кода, которую другие могут видеть и использовать для управления поведением наших объектов.

Однако чрезмерное использование модификатора public нарушает принцип инкапсуляции объектно-ориентированного программирования (ООП) и имеет несколько недостатков:

    Он увеличивает размер API, затрудняя его использование клиентами. код, потому что на него полагаются клиенты — любые будущие изменения могут нарушить их код

3. Общедоступные интерфейсы и классы

3.1. Открытые интерфейсы

Открытый интерфейс определяет спецификацию, которая может иметь одну или несколько реализаций. Эти реализации могут быть предоставлены нами или написаны другими.

Например, Java API предоставляет интерфейс Connection для определения операций подключения к базе данных, оставляя фактическую реализацию каждому поставщику. Во время выполнения мы получаем желаемое соединение на основе настройки проекта:

Connection connection = DriverManager.getConnection(url);

Метод getConnection возвращает экземпляр реализации для конкретной технологии.

3.2. Публичные классы

Мы определяем общедоступные классы, чтобы клиенты могли использовать их члены путем создания экземпляров и статических ссылок:

assertEquals(0, new BigDecimal(0).intValue()); // instance member
assertEquals(2147483647, Integer.MAX_VALUE); // static member

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

Например, среда коллекций Java предоставляет класс AbstractList в качестве основы для создания настраиваемых списков:

public class ListOfThree<E> extends AbstractList<E> {

    @Override
    public E get(int index) {
        //custom implementation
    }

    @Override
    public int size() {
        //custom implementation
    }

}

Итак, нам нужно только реализовать методы get() и size(). Другие методы, такие как indexOf() и containsAll(), уже реализованы за нас.

3.3. Вложенные общедоступные классы и интерфейсы

Подобно общедоступным классам и интерфейсам верхнего уровня, вложенные общедоступные классы и интерфейсы определяют тип данных API. Однако они особенно полезны в двух отношениях:

    Они указывают конечному пользователю API, что вмещающий тип верхнего уровня и его вложенные типы имеют логическую связь и используются вместе. Они делают нашу кодовую базу более компактной за счет уменьшения количества файлы исходного кода, которые мы бы использовали, если бы объявили их как классы и интерфейсы верхнего уровня

Примером может служить интерфейс Map.Entry из основного Java API:

for (Map.Entry<String, String> entry : mapObject.entrySet()) { }

Создание Map.Entry a вложенный интерфейс тесно связан с интерфейсом java.util.Map и избавил нас от необходимости создавать еще один файл внутри пакета java.util.

Пожалуйста, прочтите статью о вложенных классах для более подробной информации.

4. Публичные методы

Публичные методы позволяют пользователям выполнять готовые операции. Примером может служить общедоступный метод toLowerCase в String API:

assertEquals("alex", "ALEX".toLowerCase());

Мы можем безопасно сделать общедоступный метод статическим, если он не использует поля экземпляра. Метод parseInt из класса Integer является примером общедоступного статического метода:

assertEquals(1, Integer.parseInt("1"));

Конструкторы обычно общедоступны, поэтому мы можем создавать экземпляры и инициализировать объекты, хотя иногда они могут быть закрытыми, как в синглтонах.

5. Публичные поля

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

5.1. Потокобезопасность

Использование общедоступной видимости с неконечными полями или конечными изменяемыми полями не является потокобезопасным. Мы не можем контролировать изменение их ссылок или состояний в разных потоках.

Пожалуйста, ознакомьтесь с нашей статьей о потокобезопасности, чтобы узнать больше о написании ориентированного на многопотоковое исполнение кода.

5.2. Принятие мер по модификации

«У нас нет контроля над неконечным публичным полем, потому что его ссылка или состояние могут быть установлены напрямую.

Вместо этого лучше скрыть поля с помощью модификатора private и использовать общедоступный сеттер:

public class Student {

    private int age;
    
    public void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException();
        }
    
        this.age = age;
    }
}

5.3. Изменение типа данных

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

Предоставляя полям частную область видимости и используя методы доступа, мы можем гибко изменять внутреннее представление, сохраняя при этом старый тип данных:


public class Student {

    private StudentGrade grade; //new data representation
   
    public void setGrade(int grade) {        
        this.grade = new StudentGrade(grade);
    }

    public int getGrade() {
        return this.grade.getGrade().intValue();
    }
}

Единственным исключением для использования общедоступных полей является использование static final immutable поля для представления констант:

public static final String SLASH = "/";

6. Заключение

В этом руководстве мы видели, что модификатор public используется для определения API.

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

Наконец, мы обсудили, почему использование общедоступных модификаторов для полей является плохой практикой.

И, как всегда, примеры кода из этой статьи доступны на GitHub.