Классы и объекты в Java — бесплатный урок по основам ООП

Классы и объекты в Java

Бесплатный открытый урок и вход в объектное программирование: класс и объект, поля, конструктор, методы, this, toString и зачем полям нужен модификатор private. Примеры проверены на JDK 21.

Класс — это новый тип данных

В прошлых уроках данные лежали в отдельных переменных: имя в одной, балл в другой. Как только сущностей становится больше одной, такие переменные начинают путаться. Класс собирает данные и действия над ними в один тип, а объект — это конкретный экземпляр, созданный оператором new.

public class Studenty {
    public static void main(String[] args) {
        Student anna = new Student("Анна", 92);
        Student boris = new Student("Борис", 78);

        System.out.println(anna.getImya() + ": " + anna.getBall());
        System.out.println(boris);
        System.out.println("Борис сдал: " + boris.sdal());

        boris.dobavitBally(5);
        System.out.println(boris);
    }
}

class Student {
    private final String imya;
    private int ball;

    Student(String imya, int ball) {
        this.imya = imya;
        this.ball = ball;
    }

    String getImya() {
        return imya;
    }

    int getBall() {
        return ball;
    }

    void dobavitBally(int skolko) {
        ball += skolko;
    }

    boolean sdal() {
        return ball >= 60;
    }

    @Override
    public String toString() {
        return imya + " (" + ball + ")";
    }
}
Анна: 92
Борис (78)
Борис сдал: true
Борис (83)

Оба класса лежат в одном файле Studenty.java: публичным может быть только один класс, и его имя обязано совпадать с именем файла. Так удобно на время учёбы; в рабочем проекте каждый класс кладут в отдельный файл.

Разбор по частям

  • Поля imya и ball — данные объекта. У каждого экземпляра свои значения: изменение балла Бориса не трогает Анну.
  • Конструктор Student(String imya, int ball) вызывается при new и задаёт начальное состояние. Он не возвращает значения и называется так же, как класс.
  • this различает поле и параметр с одинаковым именем: this.imya — поле объекта, imya — параметр конструктора. Без this строка imya = imya присвоила бы параметр самому себе, и поле осталось бы пустым.
  • Методы dobavitBally и sdal — действия объекта. Метод, объявленный как void, ничего не возвращает.
  • toString вызывается автоматически, когда объект печатают или склеивают со строкой. Без него println(boris) вывел бы что-то вроде Student@2f92e0f4.
  • final у поля imya означает, что имя задаётся один раз при создании и больше не меняется.

Объекты в списке и статические члены

Объекты складывают в списки так же, как строки и числа. Поле со словом static принадлежит не объекту, а классу целиком: оно одно на все экземпляры, и обращаются к нему через имя класса.

import java.util.ArrayList;
import java.util.List;

public class Polka {
    public static void main(String[] args) {
        List<Kniga> polka = new ArrayList<>();
        polka.add(new Kniga("Мастер и Маргарита", 1967));
        polka.add(new Kniga("Понедельник начинается в субботу", 1965));

        for (Kniga kniga : polka) {
            System.out.println(kniga);
        }

        System.out.println("Создано книг: " + Kniga.skolkoSozdano());
    }
}

class Kniga {
    private static int sozdano = 0;

    private final String nazvanie;
    private final int god;

    Kniga(String nazvanie, int god) {
        this.nazvanie = nazvanie;
        this.god = god;
        sozdano++;
    }

    static int skolkoSozdano() {
        return sozdano;
    }

    @Override
    public String toString() {
        return nazvanie + ", " + god;
    }
}
Мастер и Маргарита, 1967
Понедельник начинается в субботу, 1965
Создано книг: 2

Метод main тоже объявлен как static — именно поэтому он запускается, когда ни одного объекта ещё не существует.

Зачем полям private

Слово private закрывает поле от постороннего кода: снаружи остаются только методы, которые вы разрешили. Это и называется инкапсуляцией. Попытка обойти её не компилируется:

public class Dostup {
    public static void main(String[] args) {
        Schet schet = new Schet(1000);
        schet.ostatok = 1000000;
        System.out.println(schet.ostatok);
    }
}

class Schet {
    private int ostatok;

    Schet(int ostatok) {
        this.ostatok = ostatok;
    }
}

Компилятор ответит ostatok has private access in Schet. Смысл не в секретности, а в контроле: если остаток меняют только методы popolnit и snyat, в них можно проверить сумму и запретить уход в минус. Открытое поле такой проверки не даёт.

Задание для самопроверки

  1. Напишите класс Tovar с полями «название», «цена» и «количество», конструктором и методом, возвращающим стоимость позиции.
  2. Соберите список из трёх товаров, напечатайте каждый через toString и посчитайте общую стоимость корзины.
  3. Закройте поле «цена» модификатором private и добавьте метод изменения цены, который отвергает отрицательные значения.

Что дальше

Это последний урок открытого раздела. Дальше начинается собственно объектное проектирование: наследование и полиморфизм, интерфейсы, исключения, equals и hashCode, разбиение программы на пакеты. Эти темы разбираются на курсе «Основы ООП на Java» с домашними заданиями и проверкой работ преподавателем — программа и условия на странице курсов.

Предыдущий урок — массивы и списки. Все бесплатные занятия собраны в разделе «Уроки Java».