Геттеры и сеттеры в Java: концепция JavaBeans - Вопросы
Всего: 5 вопросов
1. Что такое геттеры и сеттеры в Java и по каким правилам они называются?
Что такое геттеры и сеттеры в Java и по каким правилам они называются?
Геттер — это public метод, который возвращает значение поля; сеттер — public метод, который присваивает полю новое значение. Поля при этом объявляют private, поэтому обратиться к ним извне можно только через эти методы. Имя метода строится механически: берётся имя свойства, первая буква переводится в верхний регистр и добавляется префикс: name → getName() / setName(String). Геттер не принимает параметров и возвращает тип свойства; сеттер возвращает void и принимает ровно один параметр того же типа. Для примитивного boolean вместо get разрешён префикс is: isPrinted(). Пара таких методов образует свойство (property) класса, причём имя свойства определяется именами методов, а не именем поля.
2. Когда геттер можно назвать с префиксом is, а когда только get?
Когда геттер можно назвать с префиксом is, а когда только get?
Префикс is спецификация JavaBeans разрешает только для свойства примитивного типа boolean: isEnabled() и getEnabled() здесь равноправны, но is идиоматичнее — именно его генерируют IDE. Если поле имеет тип обёртки Boolean, допустим только getArchived(): класс java.beans.Introspector проверяет возвращаемый тип и метод isArchived() с типом Boolean свойством не признаёт. Практическое следствие: после замены boolean на Boolean ради поддержки null свойство молча пропадает из JSP EL, JavaFX и Spring BeanWrapper (Jackson при этом более снисходителен и is-геттер примет). Сеттер в обоих случаях называется одинаково — setEnabled(...).
3. Каким требованиям должен отвечать класс, чтобы называться JavaBean, и зачем ему конструктор без аргументов?
Каким требованиям должен отвечать класс, чтобы называться JavaBean, и зачем ему конструктор без аргументов?
JavaBean — это обычный Java-класс, оформленный по соглашению: он объявлен public, имеет public конструктор без аргументов, хранит состояние в private полях, открывает его через геттеры и сеттеры по правилам именования и (по спецификации) реализует Serializable. Конструктор без аргументов нужен потому, что фреймворк создаёт объект через рефлексию, ничего не зная о параметрах вашего конструктора: сначала вызывается new без аргументов, затем свойства заполняются сеттерами. Так работают Hibernate при загрузке сущности из базы и Jackson при разборе JSON. Как только в классе появляется конструктор с параметрами, конструктор по умолчанию исчезает, и приложение падает уже во время выполнения: InstantiationException у Hibernate, InvalidDefinitionException у Jackson. Объявляйте его явно.
4. Для чего нужны геттеры и сеттеры, если поле можно объявить public?
Для чего нужны геттеры и сеттеры, если поле можно объявить public?
Открытое поле позволяет привести объект в невозможное состояние: у класса с полями radius и diam присваивания circle.diam = 25; circle.radius = 10; компилятор пропустит, потому что Java проверяет типы, а не смысл. Ошибка проявится далеко от места возникновения. Сеттер даёт классу единственную точку входа для изменения состояния: в нём можно проверить аргумент (IllegalArgumentException на отрицательный радиус) и пересчитать связанные поля (this.diam = radius * 2), то есть сохранить инвариант. Геттер, в свою очередь, может вернуть вычисленное значение или защитную копию коллекции. Дополнительно методы доступа позволяют менять внутреннее устройство класса, не ломая вызывающий код, и делают класс пригодным для фреймворков, работающих по соглашению JavaBeans.
5. Чем record отличается от JavaBean и когда что выбирать?
Чем record отличается от JavaBean и когда что выбирать?
record (Java 16+) сам генерирует private final поля, конструктор со всеми параметрами, equals(), hashCode(), toString() и методы доступа. Но методы доступа называются по имени компонента без префикса: person.fullName(), а не getFullName(), и person.retired(), а не isRetired(). Record неизменяем: сеттеров нет в принципе, конструктор без аргументов невозможен, класс неявно final. Формально record не является JavaBean, и всё, что опирается на java.beans.Introspector, свойств у него не найдёт; современные библиотеки поддерживают records напрямую (Jackson — с версии 2.12). Выбирайте record для DTO, ответов API, ключей и результатов запросов; классический JavaBean с геттерами и сеттерами нужен там, где объект должен изменяться или где этого требует фреймворк — прежде всего для сущностей JPA/Hibernate.