1. Обзор
В этой быстрой статье мы подробно рассмотрим модификатор public
и обсудим, когда и как его использовать с классами и членами.
Кроме того, мы проиллюстрируем недостатки использования общедоступных полей данных.
Чтобы получить общее представление о модификаторах доступа, обязательно ознакомьтесь с нашей статьей о модификаторах доступа в Java .
2. Когда использовать модификатор общего доступа
Открытые классы и интерфейсы вместе с открытыми членами определяют 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, что вмещающий тип верхнего уровня и его вложенные типы имеют логическую связь и используются вместе.
- Они делают нашу кодовую базу более компактной за счет уменьшения количества файлов исходного кода, которые мы бы использовали, если бы объявили их как классы и интерфейсы верхнего уровня.
Пример — карта
.
Входной
интерфейс из основного Java API:
for (Map.Entry<String, String> entry : mapObject.entrySet()) { }
Делаем карту
.
Запись
вложенного интерфейса строго связывает его с интерфейсом 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 для представления констант:
public static final String SLASH = "/";
6. Заключение
В этом руководстве мы увидели, что модификатор public используется для определения API.
Кроме того, мы описали, как чрезмерное использование этого модификатора может ограничить возможность внесения улучшений в нашу реализацию.
Наконец, мы обсудили, почему использование общедоступных модификаторов для полей является плохой практикой.
И, как всегда, образцы кода из этой статьи доступны на GitHub .