Привет! В прошлых лекциях ты уже научился создавать собственные полноценные классы, с полями и методами. Это серьезный прогресс, молодец!
Но сейчас я вынужден сообщить тебе неприятную правду. Мы создавали наши классы не совсем правильно! Почему?
Никаких ошибок, на первый взгляд, в этом классе нет:
Название происходит от английского “get” — “получать” (т.е. “метод для получения значения поля”) и set — “устанавливать” (т.е. “метод для установки значения поля”).
Давай посмотрим, как они выглядят на примере нашего класса
Геттеры и сеттеры нужно создавать всегда. Даже если в твоих полях нет ограничений на возможные значения, вреда от них не будет.
Представь себе ситуацию: ты и твои коллеги пишете программу вместе. Ты создал класс
Можно привести аналогию с мобильным телефоном. Представь, что вместо обычного включенного мобильника тебе дали телефон cо вскрытым корпусом, где все провода, схемы и т.д. торчат наружу. Телефон при этом работает: если сильно постараться и потыкаться в схемы, может даже получится совершить звонок. Но скорее ты его просто сломаешь.
Вместо этого компания-производитель дает тебе интерфейс: клиент просто набирает нужные цифры, нажимает зеленую кнопку с трубкой — и звонок начинается. А уж что там происходит внутри со схемами и проводами и как они выполняют свою задачу — ему без разницы.
В этом примере компания ограничила доступ к “внутренностям” (данным) телефона и оставила снаружи только интерфейс (методы). В итоге клиент получит то, что хотел (совершить звонок) и точно ничего не сломает внутри.
public class Cat {
public String name;
public int age;
public int weight;
public Cat(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public Cat() {
}
public void sayMeow() {
System.out.println("Мяу!");
}
}
На самом деле — есть. Представь себе, что сидя на работе ты написал вот такой класс Cat
, обозначающий кошек. И ушел домой.
Пока тебя не было, другой программист пришел на работу, создал свой класс Main
, где начал использовать написанный тобой класс Cat
.
public class Main {
public static void main(String[] args) {
Cat cat = new Cat();
cat.name = "";
cat.age = -1000;
cat.weight = 0;
}
}
Неважно, зачем он это сделал и как так получилось: может, устал человек или не выспался.
Важно другое: наш текущий класс Cat
позволяет присваивать полям безумные значения. В результате в программе находятся объекты с некорректным состоянием, типа вот этой кошки с возрастом -1000 лет.
Какую же ошибку мы в итоге допустили?
При создании класса мы открыли его данные.
Поля name
, age
и weight
находятся в публичном доступе. К ним можно обратиться в любом месте программы: достаточно просто создать объект Cat
— и все, у любого программиста есть доступ к его данным напрямую через оператор “.
”
Cat cat = new Cat();
cat.name = "";
Здесь мы напрямую получаем доступ к полю name
и устанавливаем для него значение.
Нам нужно как-то защитить наши данные от некорректного вмешательства извне.
Что же для этого нужно?
Во-первых, все переменные экземпляра (поля) необходимо помечать модификатором private
. Private — самый строгий модификатор доступа в Java. Если ты его используешь, поля класса Cat
не будут доступны за его пределами.
public class Cat {
private String name;
private int age;
private int weight;
public Cat(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public Cat() {
}
public void sayMeow() {
System.out.println("Мяу!");
}
}
public class Main {
public static void main(String[] args) {
Cat cat = new Cat();
cat.name = "";//ошибка! Поле name в классе Cat имеет private-доступ!
}
}
Компилятор это видит и сразу выдает ошибку.
Теперь поля вроде как защищены. Но получается, что доступ к ним закрыт “намертво”: в программе нельзя даже получить вес существующей кошки, если это понадобится. Это тоже не вариант: в таком виде наш класс практически нельзя использовать.
В идеале нам нужно позволить какой-то ограниченный доступ к данным:
- Другие программисты должны иметь возможность создавать объекты
Cat
- У них должна быть возможность считывать данные из уже существующих объектов (например, получить имя или возраст уже существующей кошки)
- Также должна быть возможность присваивать значения полей. Но при этом — только корректные значения. От неправильных наши объекты должны быть защищены (никакого “возраст = -1000 лет” и тому подобного).

Cat
:
public class Cat {
private String name;
private int age;
private int weight;
public Cat(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public Cat() {
}
public void sayMeow() {
System.out.println("Мяу!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
Как видишь, всё довольно просто :) Их названия чаще всего состоят из слова get/set + названия поля, за которое они отвечают.
Например, метод getWeight()
возвращает значение поля weight
у того объекта, для которого он был вызван.
Вот как это выглядит в программе:
public class Main {
public static void main(String[] args) {
Cat barsik = new Cat("Барсик", 5, 4);
String barsikName = barsik.getName();
int barsikAge = barsik.getAge();
int barsikWeight = barsik.getWeight();
System.out.println("Имя кота: " + barsikName);
System.out.println("Возраст кота: " + barsikAge);
System.out.println("Вес кота: " + barsikWeight);
}
}
Вывод в консоль:
Имя кота: Барсик
Возраст кота: 5
Вес кота: 4
Теперь из другого класса (Main
) есть доступ к полям Cat
, но только через геттеры. Обрати внимание — у геттеров стоит модификатор доступа public
, то есть они доступны из любой точки программы.
А как обстоят дела с присваиванием значений? За это отвечают методы-сеттеры
public void setName(String name) {
this.name = name;
}
Их работа, как видишь, тоже проста. Мы вызываем метод setName()
у объекта Cat
, передаем ему в качестве аргумента строку, и эта строка присваивается в поле name
нашего объекта.
public class Main {
public static void main(String[] args) {
Cat barsik = new Cat("Барсик", 5, 4);
System.out.println("Изначальное имя кота — " + barsik.getName());
barsik.setName("Василий");
System.out.println("Новое имя кота — " + barsik.getName());
}
}
Здесь мы использовали и геттеры, и сеттеры. Вначале с помощью геттера мы получили и вывели в консоль первоначальное имя кота. Потом с помощью сеттера назначали его полю name
новое значение — “Василий”. И потом с помощью геттера получили имя снова, чтобы проверить, действительно ли оно изменилось.
Вывод в консоль:
Изначальное имя кота — Барсик
Новое имя кота — Василий
Казалось бы, в чем разница? Мы также можем присваивать полям объекта некорректные значения, даже если у нас есть сеттеры:
public class Main {
public static void main(String[] args) {
Cat barsik = new Cat("Барсик", 5, 4);
barsik.setAge(-1000);
System.out.println("Возраст Барсика — " + barsik.getAge() + " лет");
}
}
Вывод в консоль:
Возраст Барсика — -1000 лет
Разница в том, что сеттер — это полноценный метод. А в метод, в отличие от поля, ты можешь заложить необходимую тебе логику проверки, чтобы не допустить неприемлемых значений. Например, можно легко не позволить назначение отрицательного числа в качестве возраста:
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
System.out.println("Ошибка! Возраст не может быть отрицательным числом!");
}
}
И теперь наш код работает корректно!
public class Main {
public static void main(String[] args) {
Cat barsik = new Cat("Барсик", 5, 4);
barsik.setAge(-1000);
System.out.println("Возраст Барсика — " + barsik.getAge() + " лет");
}
}
Вывод в консоль:
Ошибка! Возраст не может быть отрицательным числом!
Возраст Барсика — 5 лет
Внутри сеттера есть ограничение, и оно защищает от попытки установить некорректные данные. Возраст Барсика остался без изменений.

Cat
с публичными полями, и все программисты пользуются ими, как хотят. И тут в один прекрасный день до тебя доходит: “Блин, а ведь рано или поздно кто-то может нечаянно присвоить отрицательное число в переменную weight
! Надо создать сеттеры и сделать все поля приватными!”
Ты их создаешь, и весь написанный твоими коллегами код мгновенно ломается. Ведь они уже написали кучу кода, где обращались к полям Cat
напрямую.
cat.name = "Бегемот";
А теперь поля стали приватными и компилятор выдает кучу ошибок!
cat.name = "Бегемот";//ошибка! Поле name класса Cat имеет private-доступ!
В такой ситуации лучше было бы скрыть поля и создать геттеры-сеттеры с самого начала. Все твои коллеги пользовались бы ими, и если бы тебя поздно “осенило”, что надо ограничить значения полей, ты бы просто дописал проверку внутри сеттера. И ни у кого не сломался бы уже написанный код.
Конечно, если ты хочешь, чтобы доступ к какому-то полю был только “на чтение”, можно создать для него один геттер.
“Снаружи”, то есть за пределами твоего класса, должны быть доступны только методы. Данные должны быть скрыты.

ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ