ООП ·
‹ Предыдущий Следующий ›
⏱ 5 минут чтения Обновлено: 2026-07-24

Три принципа ООП в Java

Три принципа ООП в Java — это инкапсуляция, наследование и полиморфизм. Часто к ним добавляют четвёртый — абстракцию, поэтому в литературе встречаются оба варианта: «три принципа» и «четыре принципа» объектно-ориентированного программирования. Ниже — что означает каждый из них и как он выглядит в коде на Java.

Что такое ООП и зачем оно нужно

Объектно-ориентированное программирование (ООП) — это подход, при котором программа описывается как набор взаимодействующих объектов. Объект хранит состояние (поля) и поведение (методы), а класс задаёт шаблон, по которому объекты создаются.

В отличие от процедурного подхода, где данные и функции живут отдельно друг от друга, ООП связывает их вместе. Это даёт три практических выгоды: код проще менять локально, поведение можно расширять без правки готовых классов и один и тот же вызов может работать с разными реализациями.

Java спроектирована вокруг классов: любой метод обязан находиться внутри класса или интерфейса, а точка входа main — тоже метод класса.

Инкапсуляция

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

В Java инкапсуляция обеспечивается модификаторами доступа (private, protected, package-private, public) и доступом к полям через методы.

public class BankAccount {

    private long balance;          // состояние скрыто: снаружи поле не видно

    public void deposit(long amount) {
        if (amount <= 0) {         // инвариант класса защищён
            throw new IllegalArgumentException("Сумма должна быть положительной");
        }
        balance += amount;
    }

    public long getBalance() {
        return balance;
    }
}
BankAccount account = new BankAccount();
account.deposit(500);
// account.balance = -100; // не скомпилируется: поле private
System.out.println(account.getBalance()); // 500

Ключевая мысль: инкапсуляция не про «поставить private», а про то, что класс сам отвечает за корректность своих данных. Отрицательный баланс просто невозможно создать извне.

Важно

Класс, у которого все поля private, но на каждое поле механически сгенерированы геттер и сеттер, инкапсулированным по сути не является: состояние по-прежнему меняется снаружи произвольно. Сокрытие данных — средство, а цель — сохранить инварианты объекта.

Наследование

Наследование — это свойство системы описывать новый класс на основе существующего, полностью или частично заимствуя его функциональность. Класс, от которого наследуют, называют базовым, родительским или суперклассом; новый класс — потомком, наследником или производным классом.

В Java наследование объявляется словом extends, а обратиться к реализации родителя можно через super.

public class Employee {

    protected final String name;

    public Employee(String name) {
        this.name = name;
    }

    public double salary() {
        return 1000;
    }
}

public class Manager extends Employee {

    public Manager(String name) {
        super(name);               // вызов конструктора суперкласса
    }

    @Override
    public double salary() {
        return super.salary() * 1.5;   // переиспользуем логику родителя
    }
}

Важные ограничения Java:

  • класс наследуется только от одного класса — множественного наследования классов нет;
  • реализовать при этом можно сколько угодно интерфейсов;
  • все классы неявно наследуются от java.lang.Object;
  • класс с модификатором final унаследовать нельзя (например, String).

Наследование или композиция

Наследование стоит применять, когда потомок действительно «является» частным случаем родителя (Manager — это Employee). Если нужно просто переиспользовать чужой код, лучше композиция: класс хранит другой объект в поле и делегирует ему работу. Наследование жёстко связывает классы, и изменение суперкласса ломает всех потомков.

Полиморфизм

Полиморфизм буквально означает «много форм». Это свойство системы работать с объектами через единый интерфейс, не зная их конкретного типа и внутреннего устройства. Классическая формулировка — «один интерфейс, множество реализаций».

В Java различают две формы полиморфизма.

Динамический полиморфизм (переопределение)

Реализуется через переопределение методов: какой метод вызвать, решается во время выполнения по фактическому типу объекта (динамическое связывание).

List<Employee> staff = List.of(
        new Employee("Иван"),
        new Manager("Ольга"));

for (Employee employee : staff) {
    // тип переменной — Employee, но вызывается метод фактического класса
    System.out.println(employee.salary());
}
// 1000.0
// 1500.0

Статический полиморфизм (перегрузка)

Реализуется через перегрузку: в классе несколько методов с одним именем и разными параметрами, а нужный выбирает компилятор по типам аргументов.

public class Printer {

    public void print(int value) {
        System.out.println("int: " + value);
    }

    public void print(String value) {
        System.out.println("String: " + value);
    }
}

Вопрос с собеседования

Перегрузка разрешается на этапе компиляции по объявленному типу аргумента, переопределение — на этапе выполнения по реальному типу объекта. Поэтому статические методы не переопределяются: они скрываются (method hiding) и выбираются по типу ссылки, а не объекта.

Подробный разбор термина за пределами Java — в статье Полиморфизм (информатика).

Абстракция — четвёртый принцип

Абстракция данных — это выделение значимых характеристик объекта и отбрасывание незначимых для решаемой задачи. Набор таких характеристик и есть абстракция.

Одна и та же сущность абстрагируется по-разному в зависимости от контекста: для платёжного сервиса у клиента важны идентификатор и способ оплаты, а для отдела кадров того же человека описывают должность и стаж.

В Java абстракцию выражают интерфейсы и абстрактные классы: они описывают, что объект умеет делать, ничего не говоря о том, как именно.

public interface Payment {
    void pay(long amount);            // что делаем — известно
}

public class CardPayment implements Payment {
    @Override
    public void pay(long amount) {    // как делаем — деталь реализации
        System.out.println("Оплата картой: " + amount);
    }
}

public class CashPayment implements Payment {
    @Override
    public void pay(long amount) {
        System.out.println("Оплата наличными: " + amount);
    }
}
Payment payment = new CardPayment();  // код работает с абстракцией
payment.pay(2500);                    // Оплата картой: 2500

Обратите внимание: этот пример одновременно демонстрирует абстракцию (интерфейс Payment) и полиморфизм (вызов pay() уходит в нужную реализацию). Принципы ООП работают в связке, а не по отдельности.

Сравнение четырёх принципов

Принцип Что означает Чем реализуется в Java Что даёт на практике
Инкапсуляция Данные и методы объединены, детали скрыты private, protected, геттеры и сеттеры, package-private Объект нельзя привести в некорректное состояние извне
Наследование Новый класс строится на основе существующего extends, super, Object как общий предок Повторное использование и расширение поведения
Полиморфизм Один интерфейс — много реализаций Переопределение, перегрузка, интерфейсы, дженерики Код не зависит от конкретных классов
Абстракция Отбор значимых характеристик, сокрытие лишнего interface, abstract class Модель предметной области без лишних деталей

ООП и SOLID — это разные вещи

Принципы ООП описывают, из чего состоит объектная модель. SOLID — это пять принципов проектирования, которые подсказывают, как пользоваться ООП, чтобы код оставался поддерживаемым. Их часто путают на собеседованиях, поэтому полезно держать разницу в голове.

Принцип SOLID Формулировка Пример в Java
S — Single Responsibility У класса одна причина для изменения Класс либо считает зарплату, либо печатает отчёт, но не оба сразу
O — Open/Closed Открыт для расширения, закрыт для изменения Новый способ оплаты — новая реализация Payment, старый код не трогаем
L — Liskov Substitution Потомок подставляется вместо родителя без сюрпризов Manager работает везде, где ожидается Employee
I — Interface Segregation Много узких интерфейсов лучше одного широкого Readable и Writable вместо одного Storage
D — Dependency Inversion Зависим от абстракций, а не от реализаций Поле типа Payment, а не CardPayment

Где чаще всего ошибаются

  • Считают инкапсуляцию синонимом сокрытия данных. Сокрытие — только часть: инкапсуляция ещё и объединяет состояние с поведением в одном классе.
  • Наследуют ради переиспользования кода. Если между классами нет отношения «является», получается хрупкая иерархия; композиция здесь надёжнее.
  • Путают перегрузку и переопределение. Перегрузка — одинаковое имя и разные параметры в одном классе; переопределение — одинаковая сигнатура в потомке.
  • Забывают @Override. Аннотация не обязательна, но без неё опечатка в имени метода превращает переопределение в новый метод — и компилятор промолчит.
  • Называют композицию и агрегацию принципами ООП. Это виды отношений между объектами, а не принципы; на собеседовании такой ответ засчитают как ошибку.
  • Утверждают, что Java — полностью объектно-ориентированный язык. Примитивные типы (int, double, boolean) объектами не являются, поэтому Java считают гибридным языком.

Официальное введение в объекты и классы — раздел Object-Oriented Programming Concepts в Java Tutorials от Oracle.

Часто задаваемые вопросы

Сколько принципов ООП — три или четыре?

Классическая триада — инкапсуляция, наследование и полиморфизм. Многие авторы и большинство собеседований добавляют четвёртый принцип, абстракцию. Безопасный ответ: назвать все четыре и уточнить, что абстракцию иногда рассматривают как часть инкапсуляции.

Чем полиморфизм отличается от наследования?

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

Композиция и агрегация — это принципы ООП?

Нет. Это виды отношений между объектами: агрегация означает, что объект содержит другой объект, который может существовать самостоятельно, а композиция — что вложенный объект без владельца не имеет смысла и уничтожается вместе с ним. Принципами ООП называют инкапсуляцию, наследование, полиморфизм и абстракцию.

Является ли Java полностью объектно-ориентированным языком?

Нет, Java считают гибридным языком. Весь код располагается в классах, но примитивные типы int, double, char и boolean объектами не являются, а статические методы вызываются без создания объекта. Полностью объектными считают, например, Smalltalk и Ruby.

Чем принципы ООП отличаются от SOLID?

Принципы ООП описывают устройство объектной модели языка: инкапсуляция, наследование, полиморфизм, абстракция. SOLID — это пять рекомендаций по проектированию классов, которые помогают писать поддерживаемый код поверх ООП. ООП отвечает на вопрос из чего состоит модель, SOLID — как её выстроить, чтобы она не разваливалась при изменениях.

Видео объяснение

Предпочитаете видеоформат? Посмотрите этот урок с примерами и объяснениями.

Комментарии

Зарегистрируйтесь или войдите, чтобы иметь возможность оставить комментарий.