1. Введение
Геттеры и сеттеры играют важную роль в получении и обновлении значения переменной вне инкапсулирующего класса. Сеттер обновляет значение переменной, а геттер считывает значение переменной.
В этом уроке мы обсудим проблемы неиспользования геттеров/сеттеров , их значение и типичные ошибки, которых следует избегать при их реализации в Java.
2. Жизнь без геттеров и сеттеров в Java
Подумайте о ситуации, когда мы хотим изменить состояние объекта на основе некоторого условия. Как мы могли бы добиться этого без метода установки?
- Пометка переменной как общедоступной, защищенной или по умолчанию
- Изменение значения с помощью оператора точки (.)
Давайте посмотрим на последствия этого.
3. Доступ к переменным без геттеров и сеттеров
Во-первых, для доступа к переменным вне класса без геттеров/сеттеров мы должны пометить их как общедоступные, защищенные или используемые по умолчанию. Тем самым мы теряем контроль над данными и нарушаем фундаментальный принцип ООП — инкапсуляцию .
Во-вторых, поскольку любой может напрямую изменять не частные поля извне класса, мы не можем добиться неизменности.
В-третьих, мы не можем предоставить никакой условной логики для изменения переменной. Предположим, у нас есть класс Employee
с полем PensionAge
:
public class Employee {
public String name;
public int retirementAge;
// Constructor, but no getter/setter
}
Обратите внимание, что здесь мы установили поля как общедоступные, чтобы разрешить доступ извне класса Employee
. Теперь нам нужно изменить PensionAge
сотрудника:
public class RetirementAgeModifier {
private Employee employee = new Employee("John", 58);
private void modifyRetirementAge(){
employee.retirementAge=18;
}
}
Здесь любой клиент класса Employee
может легко делать с полем PensionAge
все, что захочет . Нет способа подтвердить изменение.
В-четвертых, как мы можем получить доступ к полям только для чтения или только для записи извне класса?
Вам на помощь приходят геттеры и сеттеры.
4. Значение геттеров и сеттеров в Java
Из многих давайте рассмотрим некоторые из наиболее важных преимуществ использования геттеров и сеттеров:
- Это помогает нам достичь инкапсуляции, которая используется для сокрытия состояния объекта структурированных данных внутри класса, предотвращая несанкционированный прямой доступ к ним.
- Добейтесь неизменности, объявив поля как приватные и используя только геттеры
- Геттеры и сеттеры также предоставляют дополнительные функции, такие как проверка и обработка ошибок, которые можно будет легко добавить в будущем. Таким образом, мы можем добавить условную логику и обеспечить поведение в соответствии с потребностями.
- Мы можем предоставить разные уровни доступа к полям; например, get (доступ для чтения) может быть общедоступным, а набор (доступ для записи) может быть защищен.
- Контроль правильной установки значения свойства
- С помощью геттеров и сеттеров мы достигаем еще одного ключевого принципа ООП, то есть абстракции, которая скрывает детали реализации, чтобы никто не мог использовать поля непосредственно в других классах или модулях.
5. Как избежать ошибок
Ниже приведены наиболее распространенные ошибки, которых следует избегать при реализации геттеров и сеттеров.
5.1. Использование геттеров и сеттеров с общедоступными переменными
Доступ к общедоступным переменным можно получить вне класса с помощью оператора точки (.). Нет смысла использовать геттеры и сеттеры для публичных переменных:
public class Employee {
public String name;
public int retirementAge;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
// getter/setter for retirementAge
}
В этом случае все, что можно сделать с помощью геттеров и сеттеров, можно сделать и просто сделав поле общедоступным.
Как правило, нам нужно всегда использовать самые ограниченные модификаторы доступа, исходя из необходимости достижения инкапсуляции.
5.2. Назначение ссылок на объекты непосредственно в методах установки
Когда мы назначаем ссылку на объект непосредственно в методах установки, обе эти ссылки указывают на один объект в памяти. Таким образом, изменения, сделанные с использованием любой из ссылочных переменных, фактически выполняются в одном и том же объекте:
public void setEmployee(Employee employee) {
this.employee = employee;
}
Однако мы можем скопировать все элементы из одного объекта в другой объект, используя глубокую копию . Благодаря этому состояние этого
объекта становится независимым от существующего (переданного) объекта сотрудника:
public void setEmployee(Employee employee) {
this.employee.setName(employee.getName());
this.employee.setRetirementAge(employee.getRetirementAge());
}
5.3. Возврат ссылок на объекты непосредственно из методов получения
Точно так же, если метод получения возвращает ссылку на объект напрямую, любой может использовать эту ссылку из внешнего кода для изменения состояния объекта:
public Employee getEmployee() {
return this.employee;
}
Давайте воспользуемся этим методом getEmployee()
и изменим PensionAge :
private void modifyAge() {
Employee employeeTwo = getEmployee();
employeeTwo.setRetirementAge(65);
}
Это приводит к безвозвратной потере исходного объекта.
Итак, вместо того, чтобы возвращать ссылку из метода получения, мы должны вернуть копию объекта. Один из таких способов показан ниже:
public Employee getEmployee() {
return new Employee(this.employee.getName(), this.employee.getRetirementAge());
}
Однако мы также должны помнить, что создание копий объектов в геттере или сеттере не всегда может быть лучшей практикой. Например, вызов вышеуказанного метода получения в цикле может привести к дорогостоящей операции.
С другой стороны, если мы хотим, чтобы наша коллекция оставалась немодифицируемой, имеет смысл вернуть копию коллекции из геттера. Затем мы должны определить, какой подход лучше всего подходит в определенной ситуации.
5.4. Добавление ненужных геттеров и сеттеров
Имея геттеры и сеттеры, мы можем контролировать доступ и назначение переменных-членов. Но во многих местах это оказывается ненужным. Кроме того, это делает код многословным:
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Простое определение общедоступных геттеров и сеттеров для частного поля в классе эквивалентно тому, чтобы сделать поле общедоступным без геттеров и сеттеров. Таким образом, всегда рекомендуется обдуманно решать, определять ли методы доступа для всех полей или нет.
6. Заключение
В этом руководстве мы обсудили плюсы и минусы использования геттеров и сеттеров в Java. Мы также обсудили некоторые распространенные ошибки, которых следует избегать при реализации геттеров и сеттеров, и как правильно их использовать.