СТАТЬИ
Прокачай свои навыки Java – стань востребованным специалистом пройдя стажировку!
Вы хотите вырасти до опытного Java-разработчика и работать в крупной IT-компании?
RoadMap IT School поможет вам в освоении новых технологий Java и Spring на реальном примере в форме практической стажировки. Длительность 3 месяца. Команда из 5 человек. Тимлид уровня Senior

Основные принципы ООП в Java.

Объектно-ориентированное программирование (ООП) в Java имеет множество преимуществ, которые делают его важным инструментом для разработки программного обеспечения:
  1. Модульность: ООП позволяет разбивать программу на отдельные модули (классы), что упрощает разработку, тестирование и поддержку кода.
  2. Повторное использование кода: Благодаря наследованию и полиморфизму, можно использовать уже написанный код в новых проектах, что экономит время и усилия.
  3. Упрощение сложных систем: Абстракция и инкапсуляция помогают скрыть сложные детали реализации, предоставляя простой интерфейс для взаимодействия с объектами.
  4. Гибкость и расширяемость: ООП позволяет легко добавлять новые функции и изменять существующие, не нарушая работу всей системы.
  5. Поддержка и масштабируемость: Код, написанный с использованием ООП, легче поддерживать и масштабировать, так как он структурирован и организован.
ООП имеет уже более чем сорокалетнюю историю, но, несмотря на это, до сих пор не существует чёткого общепринятого определения данной технологии. В центре ООП находится понятие объекта. Объект в Java это сущность(экземпляр класса), которой можно посылать сообщения и которая может на них реагировать, используя свои данные.

ООП(Object-Oriented Programming) основывается на четырех основных принципах. Это инкапсуляция, наследование, полиморфизм и абстракция. Кратко рассмотрим основную идею каждого из принципа. Далее в статье мы рассмотрим их более подробно.
Итак, поехали.
  1. Инкапсуляция: Это процесс объединения данных и методов, которые работают с этими данными, в один объект. Доступ к данным осуществляется через методы, что позволяет скрыть внутреннюю реализацию и защитить данные от некорректного использования.
  2. Наследование: Это механизм, который позволяет одному классу (подклассу) наследовать свойства и методы другого класса (суперкласса). Это способствует повторному использованию кода и упрощает его поддержку.
  3. Полиморфизм: Это способность объектов разных классов реагировать на одинаковые сообщения (методы). Полиморфизм позволяет использовать один интерфейс для различных реализаций методов.
  4. Абстракция: Это процесс выделения общих характеристик объектов и создания абстрактных классов или интерфейсов, которые определяют эти характеристики. Абстракция помогает упростить сложные системы, выделяя только важные детали.
Теперь, поговорим более детально о каждом из них.

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

Инкапсуляция в Java – это принцип ООП, который заключается в сокрытии внутренних деталей реализации объекта и предоставлении внешнему окружению только необходимых методов для взаимодействия с этим объектом. Это позволяет упростить код, предотвратить нежелательное изменение состояния объекта и улучшить безопасность.
В Java инкапсуляция достигается с помощью модификаторов доступа и методов доступа (геттеров и сеттеров), а также модулей. Модификаторы доступа определяют, насколько видимыми являются переменные или методы:
  • private – доступен только внутри класса;
  • default (по умолчанию при отсутствие модификатора) – доступен внутри пакета;
  • protected – доступен внутри пакета и для наследников класса;
  • public – доступен повсюду.
Методы доступа (геттеры и сеттеры) позволяют получать и изменять значения закрытых полей класса, обеспечивая контроль над доступом к ним.
Пример инкапсуляции в Java:

class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age >= 0) {
            this.age = age;
        }
    }
}
В этом примере класс Person содержит закрытые(private) поля name и age, доступ к которым осуществляется через геттеры и сеттеры. Это позволяет контролировать, какие значения могут быть установлены для этих полей, предотвращая, например, установку отрицательного значения возраста.

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

Наследование в Java позволяет одному классу (дочернему, подклассу или производному классу) наследовать свойства и методы другого класса (родительского, суперкласса или базового класса). Это означает, что дочерний класс может повторно использовать код, поля и методы родительского класса, добавляя при этом свои собственные уникальные характеристики.
Основные аспекты наследования в Java:
  1. Суперкласс и подкласс: Класс, который наследуется, называется суперклассом или базовым классом. Класс, который наследует свойства и методы другого класса, называется подклассом или производным классом.
  2. Повторное использование кода: Наследование позволяет повторно использовать код, написанный в суперклассе, в подклассах. Это упрощает разработку, сокращает объем кода и повышает его читаемость.
  3. Переопределение методов: Дочерние классы могут переопределять методы родительского класса, что позволяет адаптировать поведение унаследованных методов к специфическим потребностям дочернего класса.
  4. Абстракция: Наследование способствует абстракции, позволяя разработчикам сосредоточиться на общих характеристиках объектов, а не на их конкретных деталях.
  5. Полиморфизм: Благодаря наследованию и переопределению методов, Java реализует полиморфизм, позволяя объектам разных типов реагировать на одни и те же сообщения по-разному.
Синтаксис наследования в Java:
Для указания наследования используется ключевое слово extends. Например:

class Bicycle {
 // методы и поля класса Bicycle
}

class MountainBike extends Bicycle {
 // методы и поля класса MountainBike, которые могут дополнять или переопределять методы Bicycle
}
В этом примере класс MountainBike наследуется от класса Bicycle, что позволяет ему повторно использовать методы и поля класса Bicycle, а также добавлять свои собственные.

Полиморфизм

Полиморфизм в Java позволяет объектам разных типов реагировать на одни и те же сообщения (методы) по-разному. Это достигается за счет комбинации наследования и переопределения методов.
Основная идея полиморфизма заключается в том, что родительский класс определяет общий интерфейс (набор методов), который наследуется дочерними классами. Однако каждый дочерний класс может реализовать эти методы по-своему, адаптируя их поведение к своим специфическим потребностям.
Рассмотрим простой пример полиморфизма в Java:

class Animal {
    public void makeSound() {
        System.out.println("Неизвестный звук");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Гав!");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Мяу!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.makeSound(); // Неизвестный звук

        Animal dog = new Dog();
        dog.makeSound(); // Гав!

        Animal cat = new Cat();
        cat.makeSound(); // Мяу!
    }
}
В этом примере класс Animal определяет метод makeSound(), который выводит сообщение “Неизвестный звук”. Классы Dog и Cat наследуются от Animal и переопределяют метод makeSound(), чтобы выводить соответствующие звуки животных.
Когда мы создаем объекты Animal, Dog и Cat, и вызываем для них метод makeSound(), каждый объект реагирует по-своему, несмотря на то, что все они используют один и тот же метод makeSound(). Это и есть проявление полиморфизма в действии.

В Java существуют два основных вида полиморфизма:
  1. Полиморфизм подтипов (Subtype Polymorphism): Этот вид полиморфизма реализуется через наследование и переопределение методов. Он позволяет использовать объекты производных классов вместо объектов базового класса, при этом вызывая методы, которые были переопределены в производных классах. Во время выполнения программы компилятор выбирает правильную версию метода на основе типа объекта. Это позволяет коду работать с объектами разных типов, но обращаться к ним через общий интерфейс (базовый класс), что делает код более гибким и расширяемым.
  2. Параметрический полиморфизм (Generics): Этот вид полиморфизма позволяет создавать обобщенные классы и методы, которые могут работать с различными типами данных. Обобщения позволяют создавать классы и методы, которые могут быть параметризованы типами данных, обеспечивая безопасность типов во время компиляции. Это помогает избежать ошибок, связанных с несоответствием типов, и делает код более надежным и безопасным.
Пример полиморфизма подтипов (Subtype Polymorphism) в Java

class Animal {
    public void makeSound() {
        System.out.println("Неизвестный звук");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Гав!");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Мяу!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.makeSound(); // Неизвестный звук

        Animal dog = new Dog();
        dog.makeSound(); // Гав!

        Animal cat = new Cat();
        cat.makeSound(); // Мяу!
    }
}
В этом примере класс Animal определяет метод makeSound(), который выводит сообщение “Неизвестный звук”. Классы Dog и Cat наследуются от Animal и переопределяют метод makeSound(), чтобы выводить соответствующие звуки животных. Когда мы создаем объекты Animal, Dog и Cat, и вызываем для них метод makeSound(), каждый объект реагирует по-своему, несмотря на то, что все они используют один и тот же метод makeSound(). Это и есть проявление полиморфизма в действии.

Пример параметрического полиморфизма (Generics) в Java

// Создание обобщенного класса Stack
class Stack<T> {
    private T[] items;
    private int size;

    public Stack(int capacity) {
        items = (T[]) new Object[capacity];
        size = 0;
    }

    public void push(T item) {
        if (size == items.length) {
            resize(2 * items.length);
        }
        items[size++] = item;
    }

    public T pop() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        return items[--size];
    }

    // Другие методы...
}

public class Main {
    public static void main(String[] args) {
        // Создание стека целых чисел
        Stack<Integer> integerStack = new Stack<>(10);
        integerStack.push(1);
        integerStack.push(2);
        System.out.println(integerStack.pop()); // Выводит 2

        // Создание стека строк
        Stack<String> stringStack = new Stack<>(5);
        stringStack.push("Hello");
        stringStack.push("World");
        System.out.println(stringStack.pop()); // Выводит World
    }
}
В этом примере создается обобщенный класс Stack, который может хранить элементы любого типа (T). Это позволяет создавать стеки для разных типов данных, таких как целые числа (Integer) или строки (String), без необходимости создавать отдельные классы для каждого типа. Использование обобщений обеспечивает безопасность типов во время компиляции, предотвращая ошибки, связанные с несоответствием типов.
Оба вида полиморфизма играют важную роль в создании гибкого и расширяемого кода в Java, позволяя разработчикам эффективно решать различные задачи и адаптироваться к изменяющимся требованиям.

Абстракция

Абстракция в Java это процесс скрытия деталей реализации и представления только функциональности. Это способ создания простых моделей сложных систем, скрывая сложные детали и выделяя необходимые функции. Абстракция помогает управлять сложностью программы, упрощая сложные системы, делая их более понятными, легко поддерживаемыми и гибкими.
Абстрактные классы и интерфейсы являются двумя основными способами создания абстракций в Java. Абстрактный класс может содержать один или более абстрактных методов, которые объявлены, но не имеют реализации. Они не могут быть использованы для создания объектов напрямую, а предназначены для наследования и дальнейшей реализации в подклассах. Интерфейсы, с другой стороны, представляют собой полностью абстрактные классы, которые могут содержать только абстрактные методы. С Java 8, интерфейсы могут также содержать методы по умолчанию(default), которые уже имеют реализацию.
Пример абстракции в Java можно увидеть на примере системы для автомобилей. Создается абстрактный класс Car с методами startEngine(), stopEngine(), accelerate() и brake(), которые являются абстрактными, поскольку их реализация будет различаться для разных типов автомобилей. Затем создаются классы ElectricCar и PetrolCar, наследующие от Car и реализующие все абстрактные методы в соответствии со своими спецификациями.

В заключение, хочется сказать следующее. Несмотря на отдельные критические замечания в адрес ООП, в настоящее время именно эта парадигма используется в подавляющем большинстве промышленных программных проектов. Однако нельзя считать, что ООП является наилучшей из методик программирования во всех случаях.
Улучши свои карьерные возможности.
Пройди стажировку и стань Middle разработчиком Java
Получи практический опыт разработки Java проекта в Agile команде с наставником. Ты можешь попробовать прямо сейчас!
Made on
Tilda